django forms ForeignKey 'value error must be an instance' - javascript

I'm trying to port an application with an existing db. I'm using db_column to have django model Foreign Keys correctly while using the existing database names and columns.
models.py
class foo(models.Model):
foo_id = models.AutoField(primary_key=True, blank=False, null=False)
foo_name = models.CharField(max_length=500, blank=True, null=True)
foo_type_lookup = models.ForeignKey('foo_type_lookup', to_field="foo_type_id", db_column="foo_type", blank=True, null=True)
class foo_type_lookup(models.Model):
foo_type_id = models.AutoField(primary_key=True, blank=False, null=False)
foo_type = models.CharField(max_length=500, blank=False, null=False)
The table foo_type_lookup has two rows (ids 0 and 1) for foo_type 'bar' and 'baz'. I'm trying to make a form to add a record in the foo table which will have a foreign key to foo_type_lookup. Foo can either be bar or baz.
views.py
def add_foo(request):
action = '#'
errors = None
if request.method == 'POST':
form = FooForm(request.POST)
if form.is_valid():
form.save(commit=True)
return home(request)
else:
# The supplied form contained errors - just print them to the terminal.
errors = form.errors
else:
# If the request was not a POST, display the form to enter details.
form = FooForm()
# Bad form (or form details), no form supplied...
# Render the form with error messages (if any).
return render(request, 'foo/add_foo.html', {'form' : form, 'errors' : errors, 'action' : action})
forms.py
CONTACT_FOO_CHOICES = [[0,'Bar'],[1,'Baz']]
class FooForm(forms.ModelForm):
foo_type_lookup = forms.ChoiceField(widget=RadioSelect(), choices=CONTACT_FOO_CHOICES)
foo_name = forms.CharField(label='First Name', max_length=500, required=False)
class Meta:
model = foo
fields = ('foo_name','foo_type_lookup')
I have to iterate over the form object in my template so I can add a jQuery function when the radio buttons are changed. I find this pretty clunky, but I'm not sure of a more django way to accomplish this:
add_foo.html
<h2>add_foo.html</h2>
<form action="{{action}}" method="post" role="form">
{% csrf_token %}
{% for field in form %}
{% if field.auto_id = 'id_foo_type_lookup' %}
{% for choice in form.foo_type_lookup.field.choices %}
<li>
<label for="id_{{ field.html_name }}_{{ forloop.counter0 }}">
<input type="radio"
id="id_{{ field.html_name }}_{{ forloop.counter0 }}"
value="{{ choice.0 }}"
{% if choice.0 == '0' %}
checked="true"
{% endif %}
name="{{ field.html_name }}"
onchange="someFunction('id_{{ field.html_name }}_{{ forloop.counter0 }}')"/>
{{ choice.1 }}
</label>
</li>
{% endfor %}
{% else %}
<div class="formfield_err">{{ field.help_text }}</div>
<div id="{{ field.auto_id }}_container" >
<div class="formfield_divlbl">{{ field.label_tag }}
</div>
<div class="formfield_divfld">{{ field }}
{% if field.field.required %}
<span class="required">*</span>
{% endif %}
</div>
<div id="{{ field.auto_id }}_errors">{{ field.errors }}
</div>
</div><div class="clear" style="margin-bottom:12px;"></div>
{% endif %}
{% endfor %}
<input type="submit" value="Submit" />
</form>
I get the error:
Cannot assign "'0'": "foo.foo_type_lookup" must be a "foo_type_lookup" instance.
How do I layout the radio buttons for the type lookup to add onchange javascript and supply my ModelForm with an object of 'foo_type_lookup' so the data will save to the database?

A ChoiceField does not know it needs to coerce the provided value to a particular model instance.
Use a ModelChoiceField instead.
https://docs.djangoproject.com/en/1.7/ref/forms/fields/#modelchoicefield
Whoops, it seems you want some very specific display logic for your values hard coded into your python which may not necessarily equate to your string representations of your related model.
If so, override your form save to apply any coercion there before the real save gets called via super.
You can also manually apply any python logic via commit=False (I notice you already have that statement set to True and perhaps you were playing with the idea.)
obj = form.save(commit=false)
obj.foo_lookup_type = MyObject.objects.get(pk=form.cleaned_data['foo_lookup_type'])
obj.save()

Related

shopify display selected variant price

I have rendered the product variants as radio buttons on liquid. Now I am trying to listen to the variant change and render different prices accordingly. However, I do not know how to listen to the variant change here.
Here is my code:
<form>
{% for product_option in product.options_with_values %}
{{ product_option.name }}
{% for value in product_option.values %}
<input type="radio" id = "{{ value }}" name="{{ product_option.name}}" value="{{ value }}" >
<label for="{{ value }}">{{ value }}</label>
{% endfor %}
<br>
{% assign current = product.selected_or_first_available_variant %}
{% endfor %}
<p>Price: {{current.price}} </p>
<input type="number" min="1">
<button type="submit">Add to Cart</button>
</form>
The price only shows for the first available variant. Even when I select different radio button options, the variant price does not update.
Welcome to stack overflow
Ideally, you probably should use some classes to use for your listeners as the page can have different radio buttons possibly even in other forms.
Below probably would get you going in the right direction.
<form>
{% for product_option in product.options_with_values %}
{{ product_option.name }}
{% for value in product_option.values %}
<input class="option" type="radio" id = "{{ value }}" name="{{ product_option.name}}" value="{{ value }}" >
<label for="{{ value }}">{{ value }}</label>
{% endfor %}
<br>
{% assign current = product.selected_or_first_available_variant %}
{% endfor %}
<p>Price: <span id="variantPrice">{{current.price}}</span></p>
<input type="number" min="1">
<button type="submit">Add to Cart</button>
</form>
You haven't mentioned if you are using jquery or not.
I'm going to assume you are.
<script>
$( document ).ready(function() {
// Load all product data to an object
var productData = {{ product | json }};
// Listen to radio button updates and trigger a function to identify the variant
$('.option').change(function() {
idSelectedVariant();
});
function idSelectedVariant(){
//1. Loop through the options and identify the selected options
//2. Once the selected options are identified, loop through the variants in the productData object and identify the selected variant by checking the variant options
//3. Keep in mind that not all product variants are going to have 3 options all the time. Some products can have 1 or 2 options as well.
//4. Once the relevant variant is identified display the variant price by updating the content in the variantPrice span.
}
});
</script>

In Django, how to make selecting a drop-down option automatically submit a form?

I'm trying to implement a form which pre-populates fields based on another field. As a starting point, I'd like to make the form 'auto-submit' when an option from a drop-down menu is selected. I've tried the following template:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script>
$(".auto-submit").change(function() {
$(this).closest("form").submit();
});
</script>
<form action="" method="post">{% csrf_token %}
{% for field in form %}
{% if field.name == "checkin_type" %}
<div class="auto-submit">
{{ field.errors }}
{{ field.label_tag }}
{{ field }}
</div>
{% else %}
<div>
{{ field.errors }}
{{ field.label_tag }}
{{ field }}
</div>
{% endif %}
{% endfor %}
<input type="submit" value="Send message" />
</form>
where the view is based on Django's generic CreateView:
from django.views import generic
from .models import CheckIn
class CheckInCreate(generic.CreateView):
model = CheckIn
fields = '__all__'
and the models are
from django.db import models
from django.urls import reverse
class CheckInType(models.Model):
title = models.CharField(blank=True, max_length=255)
description = models.TextField(blank=True)
def __str__(self):
return self.title
class CheckIn(models.Model):
checkin_type = models.ForeignKey(CheckInType, null=True, on_delete=models.CASCADE)
title = models.CharField(blank=True, max_length=255)
description = models.TextField(blank=True)
notes = models.TextField(blank=True)
# Scheduling
requested_date = models.DateField(blank=True, null=True)
completed_date = models.DateField(blank=True, null=True)
def get_absolute_url(self):
return reverse('checkin-detail', kwargs={'pk': self.id})
def save(self, *args, **kwargs):
if self.checkin_type:
if not self.title:
self.title = self.checkin_type.title
if not self.description:
self.description = self.checkin_type.description
super().save(*args, **kwargs)
However, if I actually select a drop-down menu option in the browser, nothing happens. Can someone explain why this is not working?
You're trying to attach the event handler before the drop down menu is loaded into the DOM. You can use document.ready to wait until it is loaded to attach the handler
$(document).ready(function(){
$(".auto-submit").change(function() {
$(this).closest("form").submit();
//this.form.submit(); //less verbose
});
});

Using JavaScript to render forms dynamically in Django

So I am new to Django and a complete novice at JavaScript. I am trying to create a view which renders multiple forms dynamically using JavaScript. Below are two forms that I have created.
class CreateTestForm(forms.ModelForm):
class Meta:
model = Test
fields = ['name', 'test_group', 'description', 'query_text', 'failure_condition', 'status']
def getKey(self):
return "create_test_form"
class VC1Form(CreateTestForm):
expected_relation = forms.ChoiceField(choices = [('<','<'), ('>','>'), ('=','='), ('<=','<='), ('>=','>='), ('!=','!=')], required = True, label = 'Expected Relation: ')
num_rows = forms.IntegerField()
def getKey(self):
return "vc1_form"
In addition, I have the following view
def create_test(request):
context = {
'all_validation_classes': ValidationClass.objects.all()
}
for form in [CreateTestForm, VC1Form]:
if request.method == 'POST':
f=form(request.POST)
if (f.is_valid()):
return HttpResponseRedirect('/test_created/')
else:
return HttpResponseRedirect('/test_not_created/')
else:
f = form()
context[f.getKey()] = f
return render(request, 'create_test.html', context)
And template:
<form action="/tests/create/" method="post">
{% csrf_token %}
{{create_test_form.as_ul}} <br><br>
<select id="validation_classes_id" name="all_validation_classes" onchange="showForm()">
<option value="%">Choose the validation class</option>
{% for val_class in all_validation_classes %}
<option value="{{ val_class.id }}">{{ val_class.id}} {{val_class.name }}</option>
{% endfor %}
</select>
<br><br>
<script>
function showForm(){
var x = document.getElementById("validation_class_id").value;
}
</script>
<input type="submit" value="Submit" />
I am trying to get to a point, where, when the user selects something from the dropdown (validation_classes_id), the view will render the form corresponding to that selection. I have currently included only one additional form VC1Form here but I have written different forms corresponding to each option in the drop down.
I have tried a few things but nothing has worked yet and any help would be appreciated!
Try something this:
document.getElementById('form').querySelectorAll("label").forEach( e =>
{e.prepend(document.createElement("br"));});
Even better would be:
<form id="form" action="login_view" method="post">
{% csrf_token %}
<table>
{{ form }}
</table>
<input type="submit" value="register">

How to pass parameters on onChange of html select with flask-wtf

The following flask code creates a select .. option dropdown menu:
model:
class SelectForm(Form):
country = SelectField('Country', choices=[
('us','USA'),('gb','Great Britain'),('ru','Russia')])
flask app:
#app.route('/new')
def new():
form = SelectForm()
return render_template('new.html', form = form )
html file:
<form method=post action="/register">
{{ render_field(form.country) }}
<p><input type=submit value=Register>
</form>
macro file the defines render_field:
{% 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 %}
What is the best way to have onchange submit the results automatically without the user having to press the submit button? Is there a way to change the macro or what's the most elegant way?
thanks
It can be done by add javascript onchange function as attribute
<form method=post action="/register">
{{ render_field(form.country(**{"onchange":"this.form.submit()"})) }}
<input type=submit value=Register>
</form>

Append parameter 'form id' with the URL

I have this code of HTML (Django + Jinja) .
<div class="span10 well">
{% for k in values.chat %}
<label> Text : {{k.text}} </label>
<label> {{k.date_time}} </label>
{% endfor %}
<form action = "#" method = "POST" id = {{key}} name = "reply_form">
{% csrf_token %}
{{ form.as_p }}
<input type = "submit" value = "Sent" class="btn btn-primary">
</form>
</div>
Since, there will be many chats and correspondingly reply submit button and its key, I want that when I reply to a specific chat, it carries the key with itself and process the chat accordingly.
What I need is to append the url with the form id parameter. How can I achieve this?
You can create a hidden input field
<input type="hidden" name="chat_key" value="{{key}}">
This way you can track which chatroom the person is responding by setting the value to the id of the chatroom.
EDIT: Since you are using django, on the backend to get the value of the chat_key you can just do this:
chat_key = form.cleaned_data['chat_key']

Categories

Resources