So, I want to get user input from my form (addDatabase.html) and display output of what they entered and let them download txt file with yaml formatted output (output.html).
It was working when I used Django's models.py using request.POST["fieldname"].
What I did was using JS to grab the tag of innerHTML and display out put of it
output.html JS code
var name = document.getElementById("name");
formContents += name.innerHTML + "\n";
var type = document.getElementById("type");
formContents += " " + type.innerHTML + "\n";
But my problem now is since I decided to use form.py using modelform instead of model.py. I don't know how to retrieve data from my model like i did from my model before.
output.html
<li id="type">type: {{ form.type}}</li>
<li id="vlanid">vlan_id: {{ form.vlan_id}}</li>
<li id="rdp">rdp: {{ form.rdp}}</li>
<li id="subnet">subnet:</li>
View.py (using Model from models.py)
def output(request):
Form_info.objects.all()
print("The button is clicekd")
name = request.POST["name"]
type = request.POST["type"]
vlan_id = request.POST["vlanid"]
rdp = request.POST["rdp"]
ip_master = request.POST["ipmaster"]
ip_backup = request.POST["ipbackup"]
vip = request.POST["gateway"]
nat_ip = request.POST["natip"]
cidr = request.POST["cidr"]
dns = request.POST["dns"]
dhcp = request.POST["dhcp"]
dhcp_pool_start = request.POST["dhcpstart"]
dhcp_pool_end = request.POST["dhcpend"]
form_info = Form_info(name=name, type=type, vlan_id=vlan_id, rdp=rdp, ip_master=ip_master, ip_backup=ip_backup,vip=vip, nat_ip=nat_ip, cidr=cidr, dns=dns, dhcp=dhcp, dhcp_pool_start=dhcp_pool_start,dhcp_pool_end=dhcp_pool_end)
form_info.save()
context = {
'form': form_info
}
return render(request, 'niro/output.html')
****View.py using modelform from forms.py****
This is my previous addDatabase function
def addDatabase(request):
# if this is a POST request we need to process the form data
return render(request, 'niro/addDatabase.html')
This is my current AddDatabase function
def addDatabase(request):
if request.method == 'POST':
form = YamlForm(request.POST)
if form.is_valid():
form.save()
# return HttpResponseRedirect('niro/output.html', {'form': form})
return HttpResponseRedirect('.', {'form': form})
else:
form = YamlForm()
return render(request, 'niro/addDatabase.html', {'form': form})
addDatabase.html
So post in here redirect to output.html function when the button is clicked
<div class="container">
<form action="{% url "output" %}" method="post">
{% csrf_token %}
<div class="row name">
<h3>NETWORK</h3>
</div>
<div class="row">
<div class="col-25">
<label for="">NAME:</label>
</div>
<div class="col-75">
<span class="text-danger" small>{{ form.name.errors }}</span>
{{ form.name }}
</div>
</div>
<div class="row">
<div class="col-25">
<label for="type">TYPE:</label>
</div>
<div class="col-75">
<span class="text-danger" small>{{ form.type.errors }}</span>
{{ form.type }}
.
.
.
.
<div class="row button container">
<div class="row button">
<button type="submit" value="submit">SUBMIT</button>
<button type="submit" value="submit">ADD MORE</button>
</div>
</div>
Models.py
BOOLEAN_CHOICES = (
(None, ' '),
(True, 'true'),
(False, 'false')
)
class Form_info(models.Model):
# all the columns
# example = models.CharField(null=Ture, unique=True)
name = models.CharField(max_length=50, null=True)
type = models.CharField(max_length=1, null=True)
# vlan_id = models.DecimalField(max_digits=4, decimal_places=0, null=True)
vlan_id = models.CharField(max_length=4, null=True)
rdp = models.CharField(max_length=10, null=True)
ip_master = models.CharField(max_length=15, null=True)
ip_backup = models.CharField(max_length=15, null=True)
# vip = models.GenericIPAddressField(protocol="ipv4")
vip = models.CharField(max_length=15, null=True)
nat_ip = models.CharField(max_length=15, blank=True)
# subnetmask might be devided into 2 different fields
cidr = models.CharField(max_length=18, null=True)
dns = models.CharField(max_length=15, null=True)
# boolean dropdown doesnt show
dhcp = models.CharField(null=True, max_length=10)
dhcp_pool_start = models.CharField(max_length=15, null=True)
dhcp_pool_end = models.CharField(max_length=15, null=True)
def get_absolute_url(self):
return reverse('niro:output', kwargs={'pk': self})
def __str__(self):
print("This is models.py")
return self.name + self.name + self.vlan_id + self.rdp + self.cidr + self.dhcp
So I want to modify my views.py on both functions so that way I can display userinput from the form and enables download function with existing JS code using Django modelform. Please help me!!
Related
I'm making a website where you can post jobs to an 'explore page', and I was then wondering how I would go about making it so that when a job is posted to that 'explore page', that job will also be posted to a page where the person who posted the job can manage all of the jobs they have posted i.e. edit, delete. I can post jobs to the explore page but I need to find a way for the job to save to the 'employers' page
views.py
from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required
from base.forms import JobForm
#login_required(login_url='login')
def manage_jobs(request):
if request.user.is_employee:
return redirect('home')
else:
form = JobForm(request.POST)
if form.is_valid():
form.save()
context = {"form":form}
return render(request, 'employer/manage-jobs.html', context)
urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.manage_jobs, name='manage-jobs'),
]
models.py
class Job(models.Model):
company = models.CharField(max_length=40, null=True, verbose_name="Company/Employer")
description = models.TextField(null=True)
role = models.CharField(max_length=25)
area_of_filming = models.CharField(max_length=50, verbose_name="Area Of Filming", default="")
contact_email = models.EmailField(verbose_name='Contact Email', max_length=60, default='')
created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.company
class Account(AbstractBaseUser):
email = models.EmailField(verbose_name='email', max_length=60, unique=True)
name = models.CharField(max_length=45, unique=False)
date_joined = models.DateTimeField(verbose_name='date joined', auto_now_add=True)
last_login = models.DateTimeField(verbose_name='last login', auto_now=True)
is_admin = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
is_employee = models.BooleanField(default=True, verbose_name='Are you using FilmLink as an employee?')
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['name', 'is_employee']
objects = MyAccountManager()
class Meta:
permissions = [
("post_jobs", "Can post jobs"),
]
def __str__(self):
return self.name
def has_perm(self, perm, obj=None):
return True
def has_perms(self, perm):
return True
def has_module_perms(self, app_label):
return True
#property
def is_staff(self):
return self.is_admin
manage-jobs.html
<body>
<button id="myBtn">Post A Job</button>
<div id="main"></div>
<div id="myModal" class="modal">
<div class="modal-content">
<span class="close">×</span>
<form action="" method="POST">
{% csrf_token %}
<div id="company-container">
<p>Employer Name</p>
<p id="employer">{{form.company}}</p>
</div>
<div id="role-container">
<p>Role (e.g. Actor, Director)</p>
<p id="role">{{form.role}}</p>
</div>
<div class="area-of-filming-container">
<p>Area Of Production/Filming</p>
<p id="area-of-filming">{{form.area_of_filming}}</p>
</div>
<div id="contact-email-container">
<p>Contact Email</p>
<p id="contact-email">{{form.contact_email}}</p>
</div>
<div id="description-container">
<p>Description Of Job</p>
<p id="description">{{form.description}}</p>
</div>
<button type="submit" id="post-job">Publish Job</button>
</form>
</div>
</div>
<script
src="{% static 'lng/js/manage-jobs.js' %} "
type="text/javascript"
></script>
</body>
manage-jobs.js
var modal = document.getElementById("myModal");
var btn = document.getElementById("myBtn");
var span = document.getElementsByClassName("close")[0];
btn.onclick = function() {
modal.style.display = "block";
}
span.onclick = function() {
modal.style.display = "none";
}
window.onclick = function(event) {
if (event.target == modal) {
modal.style.display = "none";
}
}
I hope I've given you enough information + code to answer my question. Sorry about the confusing wording of the title too, I struggled to put that sentence together.
The easiest way is to use ListView from django.views.generic.list.ListView
You may override get_queryset to get desired behaviour:
def get_queryset(self):
qs = super().get_queryset()
qs = qs.filter(user=self.request.user)
return qs
I'm new to Django and need some help here, I want to make a page where sellers can sell your items with coupons code and customers can get these coupons. A little mix with JS and I hid the coupon, you have to "purchase" the item, so you can have it. I have 3 tables, "Produto" (Product), "Pedido" (Order) and "Cliente" (Client) and when the custumer try to "purchase" the item, it's only appearing his/her name ! Can someone help me please ?
My view.py
#login_required(login_url='login')
def liberarForm(request, pk):
produto = Produto.objects.get(id=pk) #The Product IDs are working in admin panel
cliente = Cliente.objects.get(user=request.user)
if request.method == 'POST':
form_produto = LiberaProduto(request.POST)
form_cliente = LiberaPedido(request.POST)
if form_cliente.is_valid() and form_produto.is_valid():
form_cliente.save()
form_produto.save()
return redirect('/')
else:
form_produto = LiberaProduto(initial={'produto': produto}) #not working
form_cliente = LiberaPedido(initial={'cliente': cliente})
context = {'form_cliente': form_cliente, 'form_produto': form_produto}
return render(request, "liberar.html", context)
My form.py
class LiberaPedido(ModelForm):
class Meta:
model = Pedido
fields = '__all__'
exclude = ['produto', 'status', 'data_criado']
class LiberaProduto(ModelForm):
class Meta:
model = Produto
fields = ['nome', 'lojista', 'status', 'estoque']
My models.py
class Cliente(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
chapa = models.DecimalField(null=True, max_digits=20, decimal_places=0)
cpf = models.DecimalField(null=True, max_digits=20, decimal_places=0)
telefone = models.CharField(max_length=15, null=True)
email = models.CharField(max_length=200, null=True)
data_criado = models.DateTimeField(auto_now_add=True)
class Produto(models.Model):
STATUS = (
('Novo', 'Novo'),
('Expirado', 'Expirado'),
('Usado', 'Usado'),
)
lojista = models.CharField(max_length=200, null=True)
nome = models.CharField(max_length=200, null=True)
preco = models.DecimalField(null=True, max_digits=100, decimal_places=2)
cupom = models.CharField(max_length=200, null=True)
status = models.CharField(max_length=200, null=True, choices=STATUS)
desconto = models.FloatField(null=True)
estoque = models.BooleanField(verbose_name="Em estoque", default='Novo', null=True)
categorias = models.ManyToManyField(Categoria)
class Pedido(models.Model):
STATUS = (
('No estoque', 'No estoque'),
('Em rota', 'Em rota'),
('Entregue', 'Entregue'),
)
cliente = models.ForeignKey(Cliente, null=True, on_delete=models.SET_NULL)
produto = models.ForeignKey(Produto, null=True, on_delete=models.SET_NULL)
data_criado = models.DateTimeField(auto_now_add=True)
status = models.CharField(max_length=200, null=True, choices=STATUS, default='No Estoque')
My HTML
<form action="" method="POST">
{% csrf_token %}
{{form_cliente.as_p}}
{{form_produto.as_p}}
<input type="submit" value="Liberar">
You view code will be :-
#login_required(login_url='login')
def liberarForm(request, pk):
produto = Produto.objects.get(id=pk) #The Product IDs are working in admin panel
cliente = Cliente.objects.get(user=request.user)
if request.method == 'POST':
form_produto = LiberaProduto(request.POST)
form_cliente = LiberaPedido(request.POST)
if form_cliente.is_valid() and form_produto.is_valid():
form_cliente.save()
form_produto.save()
return redirect('/')
form_produto = LiberaProduto(initial={'nome': produto.nome, 'lojista': produto.lojista, 'status': produto.status}) #not working
form_cliente = LiberaPedido(initial={'cliente': cliente})
context = {'form_cliente': form_cliente, 'form_produto': form_produto}
return render(request, "liberar.html", context)
I have real time chat in the project, where i have two types of users: students and teachers. I want to change design of teacher messages. I tried to change consumers.py and tried to work with template but it didn't work. I think that we can do that, if we'll work with consumers.py. Who knows how to implement that?
models.py
class CustomUser(AbstractUser,mixins.GuardianUserMixin):
email = models.EmailField(_('email_address'), unique=True, name='email')
username = models.CharField(_('username'), unique=True, max_length=128)
is_student = models.BooleanField(default=False)
is_teacher = models.BooleanField(default=False)
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
objects = UserManager()
consumers.py
class Consumer(WebsocketConsumer):
def connect(self):
self.room_name=self.scope['url_route']['kwargs']['room_name']
self.room_group_name='chat_%s' % self.room_name
self.name = self.scope['user'].username
if self.scope['user'].is_anonymous:
self.send({'close':True})
else:
async_to_sync(self.channel_layer.group_add)(
self.room_group_name,
self.channel_name
)
async_to_sync(self.channel_layer.group_send)(
self.room_group_name,
{
"type":"chat_message",
"message":self.name+" Joined Chat "
}
)
self.accept()
def disconnect(self, code):
async_to_sync(self.channel_layer.group_send)(
self.room_group_name,
{
"type":"chat_message",
"message":self.name+" Left Chat"
}
)
async_to_sync(self.channel_layer.group_discard)(
self.room_group_name,
self.channel_name
)
def receive(self, text_data=None, bytes_data=None):
text_data_json=json.loads(text_data)
message=text_data_json['message']
async_to_sync(self.channel_layer.group_send)(
self.room_group_name,
{
'type':'chat_message',
'message':self.name+" : "+message
}
)
def chat_message(self,event):
message=event['message']
self.send(text_data=json.dumps({
'message':message
}))
template
<div class="ui form">
<div style="height:400px;width:100%;overflow-y:scroll" id="div_data"></div>
<input type="text" name="message" id="message" placeholder="Message" style="padding:10px;width:100%; border-radius: 0px;">
<script>
var roomName='{{ room_name }}';
var personname='{{ request.user.username }}';
var chatSocket=new WebSocket('ws://'+window.location.host+'/ws/chat/'+roomName+'/');
{% if request.user.is_anonymous %}
window.location.pathname = '{% url 'users:login' %}'
{% endif %}
chatSocket.onmessage=function(e){
var data=JSON.parse(e.data)
var message=data['message']
var div=document.querySelector("#div_data");
div.innerHTML+='<br><img class="ui avatar image" style="margin-left:2px;" src="{{user.profile.get_picture}}"><a style="padding:10px; margin-bottom:8px; " class="ui left pointing grey basic label">'+message+'</a>';
console.log(e)
}
chatSocket.onclose=function(e){
var data=JSON.parse(e.data)
console.log(data)
var message=data['message']
var div=document.querySelector("#div_data");
div.innerHTML+='<br><img class="ui avatar image" src="{% static "img/tom.jpg" %}"><a style="padding:10px; margin-bottom:8px;" class="ui right pointing teal basic label">'+message+'</a>';
}
document.addEventListener("keydown", function(event){
if(event.which == 13){
var message=document.querySelector("#message").value;
if(message.length == 0){
return false
}else{
chatSocket.send(JSON.stringify({'message':message}))
document.querySelector("#message").value=''
}
}
})
</script>
Just add a key "teacher":True or something like that to sent dictionary when a teacher sends.
You have to add some logic somewhere to know if the user is a teacher
def chat_message(self,event):
message=event['message']
dict_to_send = {'message':message}
if self.name in teachers_list:
dict_to_send['teacher'] = True
self.send(text_data=json.dumps(
dict_to_send
))
And then in js:
const data = JSON.parse(e.data);
if(data.teacher){
//this style
{
else{
//that style
}
I have a Django form with Area and Subarea. The subarea input is a ManytoManyField (not every area is a subarea but all subarea is an area), but I have to style it in the frontend, in a way that I can add and remove elements from a text input before I submit the form. I have already implemented a JavaScript function that collects all subareas in an array.
I would like to know how can I pass this array to Django, so it can go to the Subarea field and save it. Is there any possible way?
Django models.py:
class Area(models.Model):
name = models.CharField(max_length=50)
is_subarea = models.BooleanField(default=False)
Subarea = models.ManyToManyField('Area', blank=True)
def __str__(self):
return self.name
Django views.py:
class AddLanguageView(LoginRequiredMixin, CreateView):
model = Area
template_name = 'language/add-language.html'
form_class = LanguageForm
def post(self, request, *args, **kwargs):
area = Area()
area.name = request.POST.get('nome')
area.subarea = request.POST.get('Subarea')
area.save()
return render(request, 'language/add-language.html')
let sublanguageArray = [];
let i = 0;
const addSublanguage = () => {
// Add to array
const sublanguage = document.getElementById("sublanguage-input").value;
sublanguageArray.push({
name: sublanguage,
id: i
});
// Screen Preview
document.querySelector('#sublanguages').innerHTML += `
<div>
<div class="delete-sublanguage">
<img src="/static/assets/delete.png" id-delete="${i}" onclick="deleteSublanguage(this)">
</div>
${sublanguage}
</div>
`;
i++
}
// Delete html preview and from array
const deleteSublanguage = (item) => {
const block = item.parentElement.parentElement;
block.parentNode.removeChild(block);
sublanguageArray = sublanguageArray.filter(sub => sub.id !== +item.getAttribute('id-delete'));
};
<form method="POST" class="add-language-form" >
{% csrf_token %}
<div class="language-title-box" >
<h2>Linguagem:</h2>
{{ form.name }}
</div>
<div class="subarea-box">
<h2>Sub-linguagem</h2>
<input type="text" id="sublanguage-input">
<button id="submit-sublanguage" onclick="addSublanguage()">ADD</button>
<div id="sublanguages"></div>
</div>
<div class="submit-lang-box" >
<input type="submit" value="ADD AREA" id="addLanguageButton" next="partials/base.html">
</div>
</form>
I'm working on a job scheduling app for a REST API and I've created a Tasks, Nodes, URL, Adom, BaseOptions, and Jobs tables in Django. The BaseOptions have a foreign key for src_adom and dst_adom and the Jobs have foreign keys for the Task, src_node, dst_node, url and baseOptions. I didn't use a ModelForm but a generic Form instead and just loaded up the initial values and choices for all the fields I need in order to process a job. I did that because I couldn't figure out how to make the form change when the user selects a different node and want to change the select field for the corresponding adoms. I'm using javascript to detect a new node and changing the select field with the appropriate adoms for that node. I get a validation error if I change the initial source and/or destination node and modify the adom selection list. I know it is because my list of choices have changed from what I initially rendered the form with.
Is there a way to change the choices associated with a ChoiceField during the "clean" method? I can't seem to find that in the documents or digging through the Django code on github.
Models:
FMG = 'FMG'
FOS = 'FOS'
NODE_TYPE_CHOICES = (
(FMG, 'FMG'),
(FOS, 'FOS'),
)
# Create the types of tasks to run
class TaskType(models.Model):
name = models.CharField(max_length=200)
command = models.CharField(max_length=200)
node_type = models.CharField(max_length=60, choices=NODE_TYPE_CHOICES, default=FMG)
def __str__(self):
return self.name
# Create the nodes for tasks to be run on
class Node(models.Model):
ip = models.GenericIPAddressField(protocol='IPv4')
name = models.CharField(max_length=200)
apiname = models.CharField(max_length=200)
apikey = EncryptedCharField(max_length=200)
node_type = models.CharField(max_length=60, choices=NODE_TYPE_CHOICES, default=FMG)
def __str__(self):
return "{0} ({1})".format(self.name, self.ip)
class FMG_URLManger(models.Manager):
def get_queryset(self):
return super(FMG_URLManger, self).get_queryset().filter(node_type='FMG')
class FOS_URLManger(models.Manager):
def get_queryset(self):
return super(FOS_URLManger, self).get_queryset().filter(node_type='FOS')
class NodeURL(models.Model):
name = models.CharField(max_length=200)
node_type = models.CharField(max_length=60, choices=NODE_TYPE_CHOICES, default=FMG)
table_id = models.CharField(max_length=100)
table_url = models.CharField(max_length=200)
help_text = models.CharField(max_length=400, null=True)
filename = models.CharField(max_length=200)
objects = models.Manager()
fmg_objects = FMG_URLManger()
fos_objects = FOS_URLManger()
def __str__(self):
return self.name
class Adom(models.Model):
name = models.CharField(max_length=200)
version = models.CharField(max_length=60)
fmg = models.ForeignKey(Node, related_name='fmgs', on_delete=models.CASCADE)
class Meta:
unique_together = (("name", "version", "fmg"),)
def __str__(self):
return self.name
class BaseOption(models.Model):
src_adom = models.ForeignKey(Adom, related_name="src_adom", on_delete=models.CASCADE)
dst_adom = models.ForeignKey(Adom, related_name="dst_adom", on_delete=models.CASCADE, null=True)
name_filter = models.CharField(max_length=100, null=True)
site_name_filter = models.CharField(max_length=100, null=True)
policy_id_list_filter = models.CharField(max_length=60, null=True)
keep_policy_id = models.BooleanField(default=False)
disable_policy = models.BooleanField(default=False)
import_only = models.BooleanField(default=False)
def __str__(self):
return self.src_adom.name
# Create the actual request for jobs
class Job(models.Model):
UNKNOWN = 'Unknown'
PENDING = 'Pending'
SUCCESS = 'Success'
FAILURE = 'Failure'
STATUS_CHOICES = (
(UNKNOWN, 'Unknown'),
(PENDING, 'Pending'),
(SUCCESS, 'Success'),
(FAILURE, 'Failure'),
)
description = models.CharField(max_length=400)
task = models.ForeignKey(TaskType, related_name='job_task', on_delete=models.CASCADE)
src_node = models.ForeignKey(Node, related_name='src_node', on_delete=models.CASCADE)
urls = models.ManyToManyField(NodeURL)
dst_node = models.ForeignKey(Node, related_name='dst_node', on_delete=models.CASCADE)
user = models.ForeignKey(User, related_name='jobs', on_delete=models.CASCADE)
opts = models.OneToOneField(BaseOption, related_name='job', on_delete=models.CASCADE)
created = models.DateTimeField(auto_now_add=True)
run_at = models.DateTimeField(editable=True, default=timezone.now)
start = models.DateTimeField(editable=True, null=True)
finished = models.DateTimeField(editable=True, null=True)
status = models.CharField(max_length=12, choices=STATUS_CHOICES, default=UNKNOWN, editable=True)
status_text = models.TextField(editable=True, null=True)
file_location = models.CharField(max_length=4086, editable=True, null=True)
objects = models.Manager()
def __str__(self):
return self.description
The ScheduleFormView:
class ScheduleView(LoginRequiredMixin, generic.FormView):
login_url = '/login/'
redirect_field_name = 'redirect_to'
template_name = 'tools/schedule.html'
form_class = ScheduleJobForm
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
print("Got a POST request, checking for valid...")
if form.is_valid():
# <process form cleaned data>
taskID_nodeType = form.cleaned_data['task']
description = form.cleaned_data['description']
src_nodeID_name = form.cleaned_data['src_node']
dst_nodeID_name = form.cleaned_data['dst_node']
urlsID_tableID = form.cleaned_data['urls']
src_adomID = form.cleaned_data['src_adom']
dst_adomID = form.cleaned_data['dst_adom']
name_filter = form.cleaned_data['name_filter']
site_name_fiter = form.cleaned_data['site_name_fiter']
policy_id_list_filter = form.cleaned_data['policy_id_list_filter']
taskID = taskID_nodeType.split('.')[0]
src_nodeID = src_nodeID_name.split('.')[0]
dst_nodeID = dst_nodeID_name.split('.')[0]
# urlsID_tableID was a list, now it's a single URL
# urlIDs = []
# for urlID_tableID in urlsID_tableID:
# urlID = urlID_tableID.split('.')[0]
# print("Got back id {}".format(urlID))
# urlIDs.append(urlID)
urlID = urlsID_tableID.split('.')[0]
urls = NodeURL.objects.filter(id=urlID)
# print("List of URLS = {}".format(urls))
src_node = Node.objects.get(id=src_nodeID)
dst_node = Node.objects.get(id=dst_nodeID)
task = TaskType.objects.get(id=taskID)
src_adom = Adom.objects.get(id=src_adomID)
dst_adom = Adom.objects.get(id=dst_adomID)
job = Job(description=description,
task=task,
src_node=src_node,
dst_node=dst_node,
user=request.user)
opts = BaseOption(src_adom=src_adom,
dst_adom=dst_adom,
name_filter=name_filter,
site_name_filter=site_name_fiter,
policy_id_list_filter=policy_id_list_filter)
opts.save()
job.opts = opts
job.save()
for url in urls:
url.job_set.add(job)
return HttpResponseRedirect('job-list.html')
else:
print("The form was not valid. Return for more processing.")
return render(request, self.template_name, {'form': form})
The ScheduleJobForm (with my unfinished code for 'clean'):
class ScheduleJobForm(forms.Form):
def clean(self):
print("Don't actually check for on src_adom.")
cleaned_data = super(ScheduleJobForm, self).clean()
print(cleaned_data)
adom = self.cleaned_data.get("src_adom")
print(adom)
# if adom < 1:
# raise forms.ValidationError("You didn't choose a valid ADOM.")
print("Don't actually check for on dst_adom.")
cleaned_data = super(ScheduleJobForm, self).clean()
adom = self.cleaned_data.get("dst_adom")
print(adom)
# if adom < 1:
# raise forms.ValidationError("You didn't choose a valid ADOM.")
initTasks = []
selectedNodeType = ''
# Get the first node_type because it will be the default selection of tasks.
for task in TaskType.objects.all().filter(node_type='FMG').order_by('id'):
if selectedNodeType == '':
selectedNodeType = task.node_type
taskChoice = str(task.id) + '.' + task.node_type, task.name
initTasks.append(taskChoice)
# Fill in the initial Nodes for the selected task above.
initNodes = []
selectedNodeID = 0
for node in Node.objects.all().filter(node_type=selectedNodeType).order_by('id'):
nodeChoice = str(node.id) + '.' + node.name, node.name + ' (' + node.ip + ')'
if selectedNodeID == 0:
selectedNodeID = node.id
initNodes.append(nodeChoice)
# Also grab the URL's for those node types and fill them in.
initURLs = []
for url in NodeURL.objects.all().filter(node_type=selectedNodeType).order_by('table_id'):
urlChoice = str(url.id) + '.' + url.table_id, url.name
initURLs.append(urlChoice)
# Since we've got the first node selected, then all the ADOMs are the same. Get them.
initAdoms = []
for adom in Adom.objects.all().filter(fmg_id=selectedNodeID).order_by('id'):
adomChoice = adom.id, adom.name
initAdoms.append(adomChoice)
# Add some hidden fields for the jQuery script to examine.
selected_node_type = forms.CharField(initial=selectedNodeType, widget=forms.HiddenInput)
# After this, a jQuery will have to keep the select fields updated if they are changed.
task = forms.ChoiceField(choices=initTasks)
description = forms.CharField()
src_node = forms.ChoiceField(choices=initNodes)
dst_node = forms.ChoiceField(choices=initNodes)
urls = forms.ChoiceField(choices=initURLs)
# These fields will have to be updated by the jQuery to get the available ADOMS for the selected
# Nodes. We also have to create a custom validator since the choices will change via the JS.
src_adom = forms.ChoiceField(choices=initAdoms)
dst_adom = forms.ChoiceField(choices=initAdoms)
name_filter = forms.CharField()
site_name_fiter = forms.CharField()
policy_id_list_filter = forms.CharField()
The schedule.js script that modifies the adoms:
/*
Of cource, I could use the following but I think the code below is
a bit more readable.
$(function(){
initPage();
}
); */
const coreapi = window.coreapi
const schema = window.schema
$(document).ready(function(){
initPage();
}
);
function initPage() {
console.log("Adding the change code.")
// Fill in the initial srcAdom
getSrcAdom()
// and the initial dstAdom
getDstAdom()
// Hide the wait icon
$('.loading').hide();
$('#id_task').change(
function() {
var currentNodeType = $('#id_selected_node_type').val();
var selectedOption = $('#id_task option:selected').val();
var selectedNodeType = selectedOption.split(".").pop();
if (currentNodeType != selectedNodeType) {
// The more I look at the options, I think this will have to be locked
// into FMG only nodes and create another form for just FOS nodes.
}
}
);
$('#id_src_node').change(
function() {
// Need to change the src adoms
$('.loading').show();
getSrcAdom()
$('.loading').hide();
}
);
$('#id_dst_node').change(
function() {
// Need to change the src adoms
$('.loading').show();
getDstAdom()
$('.loading').hide();
}
);
}
function getSrcAdom() {
var selectedOption = $('#id_src_node option:selected').val();
var selectedNodeName = selectedOption.split(".").pop();
// Clear the src adom options.
$('#id_src_adom')
.find('option')
.remove();
// Initialize a client
var client = new coreapi.Client()
// Interact with the API endpoint
var action = ["adom", "list"]
var params = {
search: selectedNodeName,
}
client.action(schema, action, params).then(function(result) {
// Return value is in 'result'
$.each(result, function(index, obj) {
$('#id_src_adom')
.append('<option value="' + obj["id"] + '">' + obj["name"] + '</option>');
console.log(index + " got '" + obj["name"] + "' (id: " + obj["id"] + ")");
})
})
}
function getDstAdom() {
var selectedOption = $('#id_dst_node option:selected').val();
var selectedNodeName = selectedOption.split(".").pop();
// Clear the src adom options.
$('#id_dst_adom')
.find('option')
.remove();
// Initialize a client
var client = new coreapi.Client()
// Interact with the API endpoint
var action = ["adom", "list"]
var params = {
search: selectedNodeName,
}
client.action(schema, action, params).then(function(result) {
// Return value is in 'result'
$.each(result, function(index, obj) {
$('#id_dst_adom')
.append('<option value="' + obj["id"] + '">' + obj["name"] + '</option>');
console.log(index + " got '" + obj["name"] + "' (id: " + obj["id"] + ")");
})
})
}
function createNodeSelect(data) {
// This was to clear all selected nodes and list new node types.
// It's not going to be used in this form at this time.
// Need to determine data format from JSON return.
// Leaving for future code example of how to clear options
// and replace it with a single option.
$('#id_src_node')
.find('option')
.remove()
.end()
.append('<option value="whatever">text</option>')
.val('whatever');
}
The schedule.html template (with Bootstrap 4 tags):
{% extends "tools/base_site.html" %}
{% block extra_js %}
{% load static %}
<script src="{% static 'rest_framework/js/coreapi-0.1.1.js' %}"></script>
<script src="{% url 'api-docs:schema-js' %}"></script>
<script src="{% static 'js/schedule.js' %}"></script>
{% endblock %}
{% block content %}
<div id="content-main">
<br>
{% block loading %}
{% load static %}
<div id="loading" class="loading">
<img src="{% static 'images/spinning-wait-icons/wait30.gif' %}" alt="Wait" />
<!-- <h3>Loading Data from Server</h3> -->
</div>
{% endblock %}
{% load widget_tweaks %}
{% if form.errors %}
<div class="alert alert-primary">
<button type="button" class="close" data-dismiss="alert">×</button>
{% for field in form %}
{% if field.errors %}
<li>{{ field.label }}: {{ field.errors|striptags }}</li>
{% endif %}
{% endfor %}
</div>
{% endif %}
<form method="post">
{% csrf_token %}
{% for hidden_field in form.hidden_fields %}
{{ hidden_field }}
{% endfor %}
{% for field in form.visible_fields %}
<div class="form-group">
{{ field.label_tag }}
{% render_field field class="form-control" %}
{% if field.help_text %}
<small class="form-text text-muted">{{ field.help_text }}</small>
{% endif %}
</div>
{% endfor %}
<button type="submit" class="btn btn-primary">Schedule</button>
</form>
</div>
{% endblock %}
I must confess I didn't go through all the code (it's quite a lot), but at a first glance it looks to me as you should move the initialization of your choices (intTasks, initNodes...) into the __init__ method of your FormClass (ScheduleJobForm).
Because you want the code to be run when you instantiate the class, not when you load the module, right?
So:
class ScheduleJobForm(forms.Form):
selected_node_type = forms.CharField(initial=selectedNodeType, widget=forms.HiddenInput)
task = forms.ChoiceField(choices=initTasks)
# further fields
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# initialize initNodes and the rest
self.fields["src_node"]=initNodes
# and resp.
The form does not care about Javascript, as it is instantiated in the post request after all the Javascript magic on the frontend.
So there doesn't have to (and cannot) be any interaction between Javascript and your form.
I was able to figure out how to dynamically change the choices by using the getter and setter property of ChoiceField (see github repo).
The change I made was in the ScheduleJobForm view. I added these additional lines before calling 'is_valid':
print("Got a POST request, checking for valid...")
print("Fix the choices in the ADOMs first.")
src_nodeID_name = form['src_node'].value()
dst_nodeID_name = form['dst_node'].value()
src_nodeID = src_nodeID_name.split('.')[0]
dst_nodeID = dst_nodeID_name.split('.')[0]
srcAdoms = []
for adom in Adom.objects.all().filter(fmg_id=src_nodeID).order_by('id'):
adomChoice = adom.id, adom.name
srcAdoms.append(adomChoice)
dstAdoms = []
for adom in Adom.objects.all().filter(fmg_id=dst_nodeID).order_by('id'):
adomChoice = adom.id, adom.name
dstAdoms.append(adomChoice)
form.fields['src_adom'].choices = srcAdoms
form.fields['dst_adom'].choices = dstAdoms
For efficiency, I should probably check changed_data and see if the ADOM's have actually changed or not.