I have a simple form to add a website to database. This is my site model:
class Site(models.Model):
category = models.ForeignKey('Category')
category1 = models.ForeignKey('Category', related_name='+',)
subcategory = ChainedForeignKey(
'Subcategory',
chained_field='category',
chained_model_field='category',
show_all=False,
auto_choose=True)
name = models.CharField(max_length=70)
description = models.TextField()
# importuje zmienione TextFields widgets.py
keywords = MyTextField()
date = models.DateTimeField(default=datetime.now, editable=False)
url = models.URLField()
is_active = models.BooleanField(default=False)
group = models.CharField(max_length=2, choices=(('Basic',
'Basic'), ('Premium', 'Premium')))
subcategory1 = ChainedForeignKey(
'Subcategory',
chained_field='category1',
chained_model_field='category1',
related_name='subcategory1',
show_all=False,
auto_choose=True)
def get_absolute_url(self):
return "%s/%i" % (self.subcategory.slug, self.id)
class Meta:
verbose_name_plural = "Sites"
def __str__(self):
return self.name
Forms.py
class SiteAddFormFull(forms.ModelForm):
url = forms.URLField(widget=forms.TextInput(attrs={'readonly': 'readonly'}))
class Meta:
model = Site
fields = ('url', 'name', 'description', 'keywords', 'group', 'category1','subcategory1')
I would like to change my form by adding fields 'Category1', 'Subcategory1' after user choose value in group field ('Premium'). Form should reload itself and show those fields. Before choosing 'Premium' fields 'Category1', 'Subcategory1' should be invisible. How can I achieve that?
In my forms.py I added:
widgets = {'category1': forms.HiddenInput(), 'subcategory1':
forms.HiddenInput()}
In my .js file I try to show those fields but it doesn't work:
$(":hidden").show();
// $("#id_category1".show() and other posibilities
In my page soure I have
<input id="id_category1" name="category1" type="hidden" /><input id="id_subcategory1" name="subcategory1" type="hidden" />
Why it doesn't work?
You don't need HiddenInput for categories. Just hide it with jquery and show it on select change event.
<select id="group">
<option value="First">First</option>
<option value="Premium">Premium</option>
<option value="Second">second</option>
</select>
<select id="category1">
<option value="First">First</option>
<option value="Second">second</option>
</select>
Jquery
$(document).ready(function(){
$('#category1').hide();
$('#group').change(function(e) {
var group = $(this).val();
if (group == 'Premium'){
$('#category1').show();
} else {
$('#category1').hide();
}
});
});
https://jsfiddle.net/fwfm9byy/1/
Related
I have removed some useless branch from my git and now one function on my website does not work. It is about add_recipe does not work. When I am trying to add it and every field is filled, i push the button "add recipe" it shows that ingrediend field is required.
View:
def add_recipe(request):
add_recipe = RecipeForm(request.POST)
print(add_recipe['ingredients'].value())
if add_recipe.is_valid():
add_recipe.save()
return redirect('success_added_recipe')
return render(request, 'drinks/add_recipe.html', {'RecipeForm': add_recipe})
Form:
class RecipeForm(ModelForm):
class Meta:
model = Recipe
fields = ['recipe_name', 'preparation', 'ingredients', 'recipe_image']
debug.log
(0.000) SELECT "django_migrations"."app", "django_migrations"."name" FROM "django_migrations"; args=()
(0.001) SELECT "drinks_ingredient"."id", "drinks_ingredient"."ingredient_name" FROM "drinks_ingredient" WHERE "drinks_ingredient"."id" IN (12); args=(12,)
(0.000) SELECT "drinks_ingredient"."id", "drinks_ingredient"."ingredient_name" FROM "drinks_ingredient"; args=()
"POST /accounts/add_recipe/ HTTP/1.1" 200 1637
(0.002)
model:
class Recipe(models.Model):
recipe_name = models.CharField(max_length=250)
preparation = models.CharField(max_length=1000)
ingredients = models.ManyToManyField(Ingredient)
recipe_image = models.ImageField(upload_to='images/', default='')
def __str__(self):
return self.recipe_name
template:
<h1>Add recipe</h1>
<form method="post" action="{% url 'add_recipe' %}">
{% csrf_token %}
<table>
{{RecipeForm}}
</table>
<input type="submit" value="Add recipe"/>
</form>
Just add blank=True in your ManyToManyField
class Recipe(models.Model):
recipe_name = models.CharField(max_length=250)
preparation = models.CharField(max_length=1000)
ingredients = models.ManyToManyField(Ingredient,blank=True)
recipe_image = models.ImageField(upload_to='images/', default='')
def __str__(self):
return self.recipe_name
I have 2 questions:
How to code a button to be able to add 1 or more duplicate form variable in template? I want to have a product_create page with a Product that may have multiple Color and Thickness.
Then how to save the Product with multiple Color and Thickness in views.py to database? Do I need for loop?
My 4 related models in models.py:
class Product(models.Model):
product_id = models.CharField(max_length=6)
video = models.URLField(max_length=250, null=True, blank=True)
class ColorParent(models.Model):
name = models.CharField(max_length=50)
class ProductColor(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE)
color = models.ForeignKey(ColorParent, on_delete=models.CASCADE)
class ProductThickness(models.Model, MeasurementUnits):
product = models.ForeignKey(Product, on_delete=models.CASCADE)
dimension = models.PositiveIntegerField(verbose_name='Thickness in International SI unit',
null=True, blank=True)
dimension_unit = models.CharField(max_length=20,
choices=MeasurementUnits.si_base_units,
default=MeasurementUnits.millimetre, null=True, blank=True)
alias = models.CharField(verbose_name='Thickness in Imperial unit',
max_length=10, null=True, blank=True)
alias_unit = models.CharField(max_length=20,
choices=MeasurementUnits.imperial_base_units,
default=MeasurementUnits.inch, null=True, blank=True)
My forms.py:
class ProductForm(ModelForm):
class Meta:
model = Product
fields = ['product_id', 'video']
class ColorParentForm(ModelForm):
class Meta:
model = ColorParent
fields = ['name']
class ProductColorForm(ModelForm):
class Meta:
model = ProductColor
fields = ['color']
class ProductThicknessForm(ModelForm):
class Meta:
model = ProductThickness
fields = ['dimension', 'dimension_unit',
'alias', 'alias_unit']
My views.py:
def product_create_view(request):
product_form = ProductForm(request.POST, prefix='product_form')
color_form = ProductColorForm(request.POST, prefix='color_form')
thickness_form = ProductThicknessForm(request.POST, prefix='thickness_form')
if product_form.is_valid() and color_form.is_valid() and thickness_form.is_valid():
product = product_form.save() # save parent modelform first.
color = color_form.save(commit=False) # do not commit immediately for child modelform.
thickness = thickness_form.save(commit=False)
color.product = product # pair the color with created product first.
color.save() # proceed to save.
thickness.product = product
thickness.save()
context = {
'product_form': product_form,
'color_form': color_form,
'thickness_form': thickness_form,
}
return render(request, 'product_visualizers/product_create.html', context)
My current product_create.html template:
<form action="." method="post" enctype="multipart/form-data"> {% csrf_token %}
<p>Product ID {{product_form.product_id }}</p>
<p>Color Parent {{color_form.color}}</p> # Button target to add more {{color_form.color}}
<p>Video URL {{product_form.video}}</p>
<h3>Technical Specifications</h3>
<h4>Thickness Options</h4>
<p> # Button target to add more {{thickness_form.*}}
Dimension: {{thickness_form.dimension}} {{thickness_form.dimension_unit}}
Alias: {{thickness_form.alias}} {{thickness_form.alias_unit}}
</p>
<p><input type="submit" value="Save" /></p>
</form>
I try to set my field in form readonly and put any default value.
This is a part of my form:
category = forms.CharField(widget=forms.TextInput(attrs={'readonly':
'readonly'}),
initial=Category.objects.get(name='Zdrowie i uroda'))
class Meta:
model = Site
fields = ('url', 'name', 'description', 'keywords', 'group', 'category',
'subcategory', 'category1', 'subcategory1')
I get an error: Cannot assign "'Zdrowie i uroda'": "Site.category" must be a "Category" instance.
This is my site model:
class Site(models.Model):
category = models.ForeignKey('Category')
subcategory = ChainedForeignKey(
'SubCategory',
chained_field='category',
chained_model_field='category',
show_all=False,
auto_choose=True)
name = models.CharField(max_length=70)
description = models.TextField()
# importuje zmienione TextFields widgets.py
keywords = MyTextField()
date = models.DateTimeField(default=datetime.now, editable=False)
url = models.URLField()
is_active = models.BooleanField(default=False)
category1 = models.ForeignKey('Category', related_name='category', blank=True, null=True, default=None)
subcategory1 = ChainedForeignKey(
'SubCategory',
chained_field='category1',
chained_model_field='category',
related_name='subcategory',
show_all=False,
auto_choose=True, blank=True, null=True, default=None)
group = models.CharField(max_length=10, choices=(('podstawowy', 'podstawowy'),
('premium', 'premium')), default='podstawowy')
def get_absolute_url(self):
return reverse('site', args=[str(self.category.slug),
str(self.subcategory.slug), str(self.id)])
def get_thumb(self):
host = urlparse(self.url).hostname
if host.startswith('www.'):
host = host[4:]
thumb = 'http://free4.pagepeeker.com/v2/thumbs.php?size=s&url=' + host
return thumb
class Meta:
verbose_name_plural = "Strony"
def __str__(self):
return self.name
I can't deal with it. Any clues?
Finally I excluded category, subcategory fields from my model.form and added it to html source manually:
{{ form_extended|bootstrap }}
<label for="example-text-input" class="col-2 col-form-label">Category</label>
<input class="form-control form-control-lg" type="text" name="category" disabled required value="{{ form_extended.initial.category.name }} " />
<label for="example-text-input" class="col-2 col-form-label">Subcategory</label>
<input class="form-control form-control-lg" type="text" name="subcategory" disabled required value="{{ form_extended.initial.subcategory.name }} " />
I don't think it is a right way but I can't put some data to form initial values. Should I create my form manually from scratch? My way isn't good because I use jQuery to extend form. Now category, subcategory fields are las but they shouldn't (when user choose "premium" group from choice fields, after subcategory field there should appear "category1", "subcategory1" fields...
As always - I am sorry for my terrible English. Every post is like exam to me.
Options without further delving into Django forms:
Change Model Field
This might not be an option, but you could try setting:
class Site(models.Model):
category = models.ForeignKey('Category', editable=False)
Remove the explicit declaration of the category form field from your form and simply set the initial category when initializing the form or override __init__ to set it.
Change Form Field
Django would normally render a ForeignKeyField as drop down. Do you explicitly want a text input instead? In that case you have to handle data validation and the data mapping yourself.
A way of working around that would be to remove the explicit declaration of the form field and simply handle this field separatly in your HTML template:
<input type="text" name="category" value="{{ form.initial.category.name }}" />
"Do you explicitly want a text input instead?" - No.
In that case, you want a ModelChoiceField instead of a CharField.
category = forms.ModelChoiceField(
queryset=Category.objects,
empty_label=None,
disabled=True, # Django 1.9+
initial=Category.objects.get(name='Zdrowie i uroda'))
I have validation errors in my django formset. Two drop down lists, populated from the database, do not pass the validation, and I don't understand what's my mistake.
model:
class Country(models.Model):
country_code=models.CharField(max_length=2, primary_key=True)
country=models.CharField(max_length=20, unique=True)
def __unicode__(self):
return u"%s" % self.country
class Status(models.Model):
verbatim = models.ForeignKey(Verbatim)
country = models.ForeignKey(Country)
status = models.CharField(max_length=5, db_index=True)
def __unicode__(self):
return u"%s" % self.status
class Meta:
unique_together=(("verbatim", "country"), )
class ImportMinAttend(models.Model):
country=models.CharField(max_length=2, blank=False, null=False)
verbatim=models.CharField(max_length=250, blank=False, null=False)
status=models.CharField(max_length=5, blank=True, null=True, default=None)
form:
class MinAttendForm(forms.ModelForm):
country=forms.ModelChoiceField(queryset=Country.objects.all(), empty_label="Select a country")
status=forms.ModelChoiceField(queryset=Status.objects.values_list('status', flat = True).distinct(), empty_label="Select a status")
class Meta:
model=ImportMinAttend
#fields used for the validation
fields = ('country', 'verbatim', 'status')
view:
class MinAttendUpdate(UpdateView):
model = ImportMinAttend
fields = ['country', 'verbatim', 'status']
form_class=MinAttendForm
def post(self, request, *args, **kwargs):
...
MinAttendFormSet = modelformset_factory(self.model, form=self.form_class, fields=self.fields, extra=len(attendances), max_num=len(attendances)+self.nb_extra_forms)
formset=MinAttendFormSet(request.POST, queryset=attendances)
...
Source code of the first country select:
<select name="form-0-country" id="id_form-0-country">
<option value="">Select a country</option>
<option value="AT" selected="selected">Austria</option>
<option value="BE">Belgium</option>
<option value="BG">Bulgaria</option>
...
Source code of the first status select:
<select name="form-0-status" id="id_form-0-status">
<option value="">Select a status</option>
<option value="AB">AB</option>
<option value="CS">CS</option>
<option value="M" selected="selected">M</option>
</select>
About the country select: the value displayed has more than two characters but the key used has exactly 2 characters. Why this validation error?
About the status, I don't even understand the problem...
Many thanks.
EDIT: SOLVED:
I have found "dirty" workarounds.
For the country select, I use the key of the select, not the value:
def clean_country(self):
data = self.cleaned_data['country'].pk
return data
For the status select, I delete the validation error if a value is selected:
def clean(self):
#call status clean method
self.cleaned_data["status"]=self.clean_status()
return self.cleaned_data
def clean_status(self):
#valid if a value has been selected
if self["status"].value()!="":
del self._errors["status"]
return self["status"].value()
It works, but why do I have to do this? :(
I think you are doing it the hard way. There is a lot easier way to do it, taking advantage of ModelForm. Here is a full example. Read it and adapt it to your models:
from django.db import models
from django.forms import ModelForm
TITLE_CHOICES = (
('MR', 'Mr.'),
('MRS', 'Mrs.'),
('MS', 'Ms.'),
)
class Author(models.Model):
name = models.CharField(max_length=100)
title = models.CharField(max_length=3, choices=TITLE_CHOICES)
birth_date = models.DateField(blank=True, null=True)
def __str__(self): # __unicode__ on Python 2
return self.name
class Book(models.Model):
name = models.CharField(max_length=100)
authors = models.ManyToManyField(Author)
class AuthorForm(ModelForm):
class Meta:
model = Author
fields = ['name', 'title', 'birth_date']
class BookForm(ModelForm):
class Meta:
model = Book
fields = ['name', 'authors']
I want to pass a dropdown variable from the template to a function when i click submit button
#models.py :-
class donnee(models.Model):
name = models.CharField(_('name'), max_length= 150)
def __unicode__(self):
return self.name
class Meta:
verbose_name = _('donnee')
verbose_name_plural = _('donnees filtrage')
ordering = ['name']
class Property(models.Model):
name = models.CharField(_('name'), max_length=50)
description = models.TextField(_('description'), blank=True)
def __unicode__(self):
return self.name
class Meta:
verbose_name = _('property')
verbose_name_plural = _('properties')
ordering = ['name']
class Physic2(models.Model):
name = models.ForeignKey(Property, verbose_name=_('name'), null=True, blank=True)
lapropriete = models.ForeignKey(donnee, verbose_name=_('lapropriete'), blank=True)
#lapropriete = models.CharField(_('property'), max_length=100)
description = models.TextField(_('description'), blank=True)
def __unicode__(self):
return self.lapropriete
class Meta:
verbose_name = _('physic2')
verbose_name_plural = _('physics2')
ordering = ['name']
#forms.py:-
class Physic2Form(forms.ModelForm):
class Meta:
model = Physic2
#views.py:-
def get_materials_one(request, category_slug=None):
if category_slug is None:
lafamille= 'general'
propriete= Physic2Form()
return render_to_response('material/critere1.html',
{'unefamille': lafamille,
'propriete': propriete},
context_instance=RequestContext(request))
#template:-
<form id= "testjson" action="{% url chercher_filtre1 %}" method= "get" onsubmit = "">
{{ propriete.lapropriete }}
<td><input type="submit" style="background-color:#D7D8D4;" value="Search" id= "chercher"/></td>
</div>
</form>
#function:-
valT1 = request.GET['lapropriete']
this don't work
when i click on a field in the dropdown list
valT1 = 1 or 2... it's just the id of the field
i have the fields
Vickers hardness (GPa)
Shear Modulus (GPa)
Young Modulus (GPa)
what to put for request.GET[ ??]
You can write like this and try.
if request.method == 'GET':
form = Physic2Form(request, data=request.GET)
if form.is_valid():
data = form.cleaned_data
valT1 = data['lapropriete']
my function
def search_filter1(request):
try:
val_min1 = float(request.GET['Vmin1'])
val_max1 = float(request.GET['Vmax1'])
T_min1 = float(request.GET['Tmin1'])
T_max1 = float(request.GET['Tmax1'])
if request.method == 'GET':
form = Physic2Form(request.GET)
if form.is_valid():
valT1 = form['lapropriete']
print 'val_min1:',val_min1
print 'val_max1:',val_max1
print 'Tmin1:', T_min1
print 'Tmax1:', T_max1
print 'valT1:',valT1
If i select the property 'Shear Modulus (GPa)' when i click on submit button,
i get this :
val_min1: 44.0
val_max1: 99.0
Tmin1: 44.0
Tmax1: 99.0
valT1: <select name="lapropriete" id="id_lapropriete">
<option value="">---------</option>
<option value="2">Elasticity Modulus (GPa)</option>
<option value="4" selected="selected">Shear Modulus (GPa)</option>
<option value="1">Vickers Hardness (GPa)</option>
<option value="3">Young Modulus (GPa)</option>
</select>
why that ?