this is my code and I try to show the label but it is not displaying
this is my form file
forms.py
class ReviewForm(ModelForm):
class Meta:
model = Review
fields = ['value', 'body']
labels = {'value': 'Place your vote', 'body': 'Add a comment with your vote'}
def __init__(self, *args, **kwargs):
super(ReviewForm, self).__init__(*args, **kwargs)
for name, field in self.fields.items():
field.widget.attrs.update({'class': 'input'})
this is my views file and the function for this form
views.py
def project(request, pk):
projectObj = Project.objects.get(id=pk)
form = ReviewForm()
context = {
'project': projectObj,
'form': form
}
return render(request, 'projects/single-project.html', context)
this is the model for the review section
models.py
class Review(models.Model):
VOTE_TYPE = (
('up', 'Up Vote'),
('down', 'Down Vote')
)
owner = models.ForeignKey(Profile, on_delete = models.CASCADE, null=True)
project = models.ForeignKey(Project, on_delete=models.CASCADE)
body = models.TextField(null=True, blank=True)
value = models.CharField(max_length=200, choices=VOTE_TYPE)
created = models.DateTimeField(auto_now_add=True)
id = models.UUIDField(default = uuid.uuid4, unique=True, primary_key=True, editable=False)
class Meta:
# every user can only have single comment on each project
unique_together = [['owner', 'project']]
def __str__(self):
return self.value
and the html file to display the form
html file
<form class="form" action="{% url 'project' project.owner.id %}" method="POST">
{% csrf_token %}
{% for field in form %}
<div class="form__field">
<label for="formInput#textarea">{{field.label}}</label>
{{field}}
</div>
{% endfor %}
<input class="btn btn--sub btn--lg" type="submit" value="Comments" />
</form>
I try to show form.label but it is not displaying
the label is contained in the label_tag property in the field:
<form class="form" action="{% url 'project' project.owner.id %}" method="POST">
{% csrf_token %}
{% for field in form %}
<div class="form__field">
<label for="formInput#textarea">{{field.label_tag}}</label>
{{field}}
</div>
{% endfor %}
<input class="btn btn--sub btn--lg" type="submit" value="Comments" />
</form>
Are you sure for your labels property of Meta class of ModelForm, i do not known this property. You probably need to redefine your field with label you want to, or update field label in the init function of your form.
class ReviewForm(ModelForm):
class Meta:
model = Review
fields = ['value', 'body']
labels = {'value': 'Place your vote', 'body': 'Add a comment with your vote'}
def __init__(self, *args, **kwargs):
super(ReviewForm, self).__init__(*args, **kwargs)
for name, field in self.fields.items():
field.widget.attrs.update({'class': 'input'})
Related
I am trying to use a modelchoicefield from the form in a formset_factory but i dont understand the error and don't know how to solve it.
(edit added the models.py)
models.py
class Order(Model):
user = ForeignKey(User, on_delete=SET_NULL, null=True)
fee = ForeignKey(Fee, on_delete=SET_NULL, null=True)
route = ForeignKey(Route, on_delete=SET_NULL, null=True)
price_rate = ForeignKey(PriceRate, on_delete=SET_NULL, null=True)
pallet_amount = IntegerField()
status = BooleanField()
postal_code = CharField(max_length=6)
city = CharField(max_length=255)
street = CharField(max_length=255)
delivery_from = DateTimeField()
delivery_until = DateTimeField(null=True)
created_at = DateTimeField(auto_now_add=True, blank=True)
updated_at = DateTimeField(auto_now=True)
deleted_at = DateTimeField(null=True, blank=True)
views.py
def routecreate_view(request):
orderformset = formset_factory(OrdersRouteForm, can_delete=False, extra=1)
if request.method == 'POST':
form = RouteForm(request.POST)
formset = orderformset(request.POST)
if form.is_valid() and formset.is_valid():
# process the data in form.cleaned_data as required
messages.success(request,
"You succesfully created an route.")
return HttpResponseRedirect(reverse('planner.dashboard'))
else:
form = RouteForm()
formset = orderformset()
return render(request, 'planner/route.html', {'form': form, 'formset': formset})
forms.py
class OrdersRouteForm(forms.ModelForm):
route = ModelChoiceField(
queryset=Order.objects.filter(status=1, delivery_until__gte=datetime.datetime.now(), deleted_at=None),
label='Order')
class Meta:
model = Order
fields = ("route",)
def __init__(self, *args, **kwargs):
super(OrdersRouteForm, self).__init__(*args, **kwargs)
for visible in self.visible_fields():
visible.field.widget.attrs['class'] = 'form-control m-2'
self.fields['route'].label_from_instance = self.label_from_instance
#staticmethod
def label_from_instance(obj):
return "pallets: %s, %s, %s, %s" % (obj.pallet_amount, obj.street, obj.city, obj.postal_code)
template:
{% extends 'base.html' %}
{% block base %}
<div class="container rounded bg-white mt-5 mb-5">
<div class="row">
<div class="col-md-5 border-right mx-auto">
planner//route
<div class="p-3 py-5">
<form id="form-container" method="POST">
{% csrf_token %}
{{ form }}
{{ formset }}
<button id="add-form" type="button">Add Another Bird</button>
<button class="btn btn-danger profile-button mt-3" onclick="window.history.back()">Cancel
</button>
<button class="btn btn-primary float-end mt-3" type="submit">Order</button>
</form>
</div>
</div>
</div>
</div>
{% endblock %}
error:
Cannot assign "<Order: Order object (2)>": "Order.route" must be a "Route" instance.
The error occurs when i fill the formset with request.POST and then try to send the formset to the template.
I have tried an inlineformset and modelformset and didnt get it to work. ANY solution is welcome.
The problem seemed to be with the modelform. I removed this from the code:
class Meta:
model = Order
fields = ("route",)
I don't understand why this caused the problem and if anyone knows and can explain it please feel free to do so.
hope it helps anyone else with this problem.
models.py
class Products(models.Model):
Name = models.CharField(max_length=100, verbose_name='Name of Product')
Category = models.CharField(max_length=100, verbose_name='Product Category')
Description = models.CharField(max_length=220, verbose_name='Product Description')
class Categories(models.Model):
Title = models.CharField(max_length=100, verbose_name='Category Title')
Description = models.CharField(max_length=100, verbose_name='Category Description')
Picture = models.ImageField(default='/gifts.png', upload_to='ffff/')
def __str__(self):
return self.Title
forms.py
class EditProduct(forms.ModelForm):
class Meta:
model = Products
fields = ['Name', 'Category', 'Description', 'Weight', 'Size', 'Cost', 'Personalised', 'Keywords',
'Picture1']
widgets = {
'Category': Select(),
}
def __init__(self, *args, **kwargs):
super(EditProduct, self).__init__(*args, **kwargs)
self.fields['Category'] = forms.ModelChoiceField(queryset=Categories.objects.all().order_by('Title'))
I've created records in models.py Categories (eg Title = 1, Title, 2, Title =3)
In models.py Products i have created some records (eg Name=Hat, Category=1; Name=Cap, Category=3)
I can add Product records easily with crispy forms and my drop down list appears for Category, select the choice and form saves. All works great
But when i try to EDIT the record, i use instance= and it brings the contents of the record back, but i also want a drop down list for category in the edit section, but if i put a drop-down list in, then it doesn't populate that field with existing value, i need to reselect it
My views.py
def products_edit(request, item_id):
pp = Products.objects.get(id=item_id)
my_form = EditProduct(instance=pp)
if 'first' in request.POST:
if request.method == 'POST':
my_form = EditProduct(request.POST, request.FILES, instance=pp)
if my_form.is_valid():
my_form.save()
messages.success(request, f'Thank you the Product has been amended!')
return redirect('frontpage-products')
context = {
'my_form': my_form,
'results': Products.objects.all().order_by('Name')
}
return render(request, 'frontpage/products_edit.html', context)
and my html
<form method="POST" class="form-section" enctype="multipart/form-data">
<div class="page_font search">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Edit Product</legend>
{{ my_form|crispy }}
</fieldset>
<div class="form-group">
<button class="btn btn-primary" type="submit" name="first">UPDATE</button>
</div>
</div>
</form>
How do i populate the drop-down list with existing value?
I am struggling with Django forms.
I have the following model.py:
class Property(models.Model):
portfolio = models.ForeignKey("portfolios.Portfolio", on_delete=models.CASCADE)
class PropertyImage(models.Model):
property = models.ForeignKey("Property", on_delete=models.CASCADE)
image = models.ImageField(upload_to = property_image_upload_to)
def __str__(self):
return self.image.url
class PropertyDocument(models.Model):
property = models.ForeignKey("Property", on_delete=models.CASCADE)
document = models.FileField()
class Address(models.Model):
property = models.OneToOneField("Property", on_delete=models.CASCADE)
line1 = models.CharField(max_length=100)
line2 = models.CharField(max_length=100, null=True, blank=True)
line3 = models.CharField(max_length=100, null=True, blank=True)
post_code = models.CharField(max_length=7)
town = models.CharField(max_length=100, null=True, blank=True)
city = models.CharField(max_length=100)
When adding/updating a property, I want the form to show the form for related objects like the address, documents/images instead of the select list's that appear in forms - I want to be able to add/edit the related data.
My view.py file
class PropertyCreate(CreateView):
model = Property
form_class=PropertyAddressFormSet
success_url = reverse_lazy('Property_list')
def get_context_data(self, **kwargs):
data = super(PropertyCreate, self).get_context_data(**kwargs)
return data
Property_form.html
{% extends 'base/base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<form method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" class="btn btn-primary" />
<button class="btn btn-link" onclick="javascript:history.back();">Cancel</button>
</form>
{% endblock %}
urls.py
from . import views
app_name = 'properties'
urlpatterns = [
path('<int:portfolio_id>/<int:pk>/edit', views.PropertyUpdate.as_view(), name='property_edit'),
path('<int:portfolio_id>/create', views.PropertyCreate.as_view(), name='property_new'),
]
I've read about inlineformset_factories and inlineformset's etc, but is this the best choice for my scenario? If so, I can't figure out how to show the portfolio, address form
I;m currently using a inlineformset like so, which creates the Address form on the PropertyCreate view, but I want to also add in the PropertyImages and PropertyDocs to the ProertyCreate view.:
PropertyAddressFormSet = inlineformset_factory(
parent_model=Property,
model=Address,
form=AddressForm,
extra=0,
min_num=1
)
For anyone in the same boat as me, I managed to get this working with the following code:
Forms.py:
class PropertyForm(ModelForm):
""" Edit a property """
class Meta:
model = Property
exclude = ()
PropertyAddressFormSet = inlineformset_factory(
parent_model=Property,
model=Address,
form=AddressForm,
extra=0,
min_num=1
)
Views.py
class PropertyCreate(CreateView):
model = Property
form_class=PropertyForm
success_url = reverse_lazy('Property_list')
def get_context_data(self, **kwargs):
data = super(PropertyCreate, self).get_context_data(**kwargs)
if self.request.POST:
data['address'] = PropertyAddressFormSet (self.request.POST, instance=self.object)
else:
data['address'] = PropertyAddressFormSet ()
return data
template:
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form |crispy }}
<fieldset class="border p-2">
<legend class="w-auto">Address</legend>
{{ address.management_form }}
{% for form in address.forms %}
<div >
{{ form.as_p }}
</div>
{% endfor %}
</fieldset>
</form>
Hope this helps someone.
I changed ModelChoiceField to be shown as a TextInput.
I have a field named 'filename' of this type: models.ForeignKey('Filename', on_delete=models.SET_NULL, null=True, blank=True) in a class as follow:
models.py
class Event(models.Model):
name = models.CharField('Name', max_length=100, blank=True, default='')
filename = models.ForeignKey('Filename', on_delete=models.SET_NULL, null=True, blank=True)
class Filename(models.Model):
name = models.CharField('Name', max_length=50)
def __str__(self):
return self.nome
This is part of my 'forms.py' I use show form in frontend after defining the template (myappname/templates/myappname/event_edit.html)
forms.py
class EventEditForm(forms.ModelForm):
def __init__(self, data=None, *args, **kwargs):
if data is not None:
data = data.copy()
if data['filename']:
f, f_created = Filename.objects.get_or_create(nome=data['filename'])
data['filename'] = m.id
super(EventEditForm, self).__init__(data=data, *args, **kwargs)
self.fields['filename'] = forms.ModelChoiceField(queryset=Filename.objects.all(), widget=forms.TextInput(attrs={'class': 'form-control', 'value':self.instance.filename}))
self.fields['filename'].required = False
class Meta:
model = Event
fields = ['name', 'filename']
and this is my event_edit.html:
<form method="post" class="form-horizontal">
{% csrf_token %}
{% for field in event_form %}
<div class="form-group form-group-lg">
<label for="{{ field.id_for_label }}" class="col-sm-2 control-label">{{field.label}}</label>
<div class="col-sm-6">
{{ field }}
</div>
<div class="col-sm-4">
{{ field.errors }}
</div>
</div>
{% endfor %}
<div class="form-group">
<div class="col-sm-10">
<button type="submit" class="btn btn-primary btn-lg center-block">Save</button>
</div>
</div>
</form>
The problem is that if I override ModelChoiceField to be a TextInput the 'filename' field shows id instead of showing field name.
Otherwise, If I leave it as a Choice Field it correctly shows value instead of id.
How can I solve this issue?
Based on your comments and the code in EventEditForm, you want a form that will:
display the Event.name and the linked Filename.name
use the submitted name to update Event.name
use the submitted filename to lookup or create a Filename and update Event.filename
This should work:
class EventEditForm(forms.ModelForm):
"""
Calling form.save() will:
* update the Event.name
* update the Event.filename with a Filename instance
found or created using the supplied name
"""
fname = forms.CharField(
label='Filename',
required=False,
widget=forms.TextInput(attrs={'class': 'form-control'}),
)
class Meta:
model = Event
fields = ['name',]
widgets = {
'name': forms.TextInput(attrs={'class': 'form-control'}),
}
def __init__(self, *args, **kwargs):
super(EventEditForm, self).__init__(*args, **kwargs)
self.initial['fname'] = self.instance.filename
def save(self, commit=True):
instance = super(EventEditForm, self).save(commit=False)
cleaned_fname = self.cleaned_data['fname']
if cleaned_fname:
f, f_created = Filename.objects.get_or_create(name=cleaned_fname)
instance.filename = f
else:
instance.filename = None
if commit:
instance.save()
return instance
Radio-buttons are not showing, its the check-boxes displayed in the Class Based Views. I want them to be showing the radio-buttons
forms.py
class ProductImagesForm(forms.ModelForm):
media = forms.ImageField(label='Image')
def __init__ (self, *args, **kwargs):
super(PerstransForm, self).__init__(*args, **kwargs)
self.fields['featured_image'] = forms.BooleanField( widget = forms.RadioSelect(choices=((self.prefix, 'featured'),))
def add_prefix(self, field):
if field == 'featured_image': return field
else: return self.prefix and ('%s-%s' % (self.prefix, field)) or field
class Meta:
model = ProductImages
fields = ['media', 'featured_image']
ImagesFormset = modelformset_factory(ProductImages, fields=('media', 'featured_image'), extra=1)
models.py
def product_download(instance, filename):
return '%s/%s' %(instance.product.slug, filename)
class ProductImages(models.Model):
product = models.ForeignKey(Product)
title = models.CharField(max_length=120)
media = models.ImageField(upload_to=product_download,
width_field='max_width',
height_field='max_height',
null=True, blank=True)
max_width = models.CharField(max_length=100, null=True, blank=True)
max_height = models.CharField(max_length=100, null=True, blank=True)
featured_image = models.BooleanField(default=True)
timestamp = models.DateTimeField(auto_now_add=True, auto_now=False)
updated = models.DateTimeField(auto_now_add=False, auto_now=True)
def __unicode__(self):
return unicode(self.media)
class Meta:
verbose_name = "product image"
verbose_name_plural = "product images"
Views.py
def get(self, *args, **kwargs):
self.object = self.get_object()
form_class = self.get_form_class()
form = self.get_form(form_class)
formset = ImagesFormset(queryset=ProductImages.objects.none())
return self.render_to_response(self.get_context_data(form=form, formset=formset))
def post(self, request, *args, **kwargs):
self.object = self.get_object()
form_class = self.get_form_class()
form = self.get_form(form_class)
formset = ImagesFormset(self.request.POST, self.request.FILES)
form_valid = form.is_valid()
formset_valid = formset.is_valid()
if form_valid and formset_valid:
seller = self.get_account()
form.instance.seller = seller
self.object = form.save()
media = formset.save(commit=False)
for img in media:
img.product = self.object
img.save()
formset.save()
return self.form_valid(form, formset)
else:
return self.form_invalid(form, formset)`
template
<form enctype="multipart/form-data" action="" method="post"> {% csrf_token %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{{ form.as_p }}
{{ formset.management_form }}
<div class="link-formset">
{{ formset }}
{% for choice in formset.featured_image %}
<ul>
<li><input type="radio" name="featured"></li>
</ul>
{% endfor %}
</div>
<input type="submit" value="{{ submit_btn }}">
</form>
Hope someone can help me to fix in the missing pieces
This will happen because you choose BooleanField that means a specific selection is either 0 or 1 and radio button is used to select one option from multiple choices hence you should try using forms.ChoiceField instead of forms.BooleanField.
for more details read this official django doc
I have got to some point and I guess it will help some folks
template
{{ formset.management_form }}
<div class="link-formset">
{% for choice in formset %}
<div>
{{ choice.media }}
<input type="radio" name="{{choice.featured_image.label}}">{{ choice.featured_image.label }}</
</div>
{% endfor %}
</div>