how to add css class to radio button in django template - django

I am trying to do the following with django widget tweaks:
{{ form.gender.0.tag|attr:"class:radio_1" }}
I get the error:
'SafeText' object has no attribute 'as_widget'
What am I doing wrong?

Initialize your RadioButton like this:
CHOICES=[('option1','option1'),
('option2','option2')]
radio = forms.ChoiceField(choices=CHOICES, widget=forms.RadioSelect(attrs={'class': 'radio_1'}))
and the generated HTML-Code will look like this:
<input type="radio" class="radio_1" ... />

You may have figured out already how to apply CSS to radio buttons in Django template but in case someone is in the same situation, here's a code straight from the docs:
<fieldset>
<legend>{{ myform.beatles.label }}</legend>
{% for radio in myform.beatles %}
<div class="myradio">
{{ radio }}
</div>
{% endfor %}
</fieldset>
This code assumes you have a form myform with a field beatles that uses a RadioSelect as its widget.
As you can see, looping through the field beatles can allow you to add necessary classes (here class="myradio") for each radio button; hence, make your CSS styling possible and easier.
In your case, you might want to also loop through your gender field and then apply the appropriate classes.

Related

How to pass a <select> in a View using Django

I was trying to make a cart system in Django and wanted to pass Size and the Quantity of product as <Select>
input in View.
My Template have :
<ul class="list-unstyled">
Select Size:
<select name="sizes">
{% for size in product.sizes.all %}
<li class="list-item list-inline-item"><option value="{{size.nameSize}}">{{size.nameSize}}</option> </li>
{% endfor %}
</select>
</ul>
This is how it looks :
But when i Submit it using the Add to Cart Button i get error:
This is the code in the view:
def add_item(request,pk):
product = get_object_or_404(Product,pk=pk)
size = request.POST['sizes']
selectsize = Size.objects.get(nameSize=size)
user = request.user
usercart = Cart.objects.get(owner=user)
newitem = CartItems.objects.create(cart = usercart,product=product,size=selectsize)
items = usercart.cartitems
return render(request,'cart.html',{'cartitems':items})
I am trying to use the name of the size from the Template and compare the size name i have in the database for that product Using:
selectsize = Size.objects.get(nameSize=size)
I was able to get size with name 36 so i wanted to pass the value 36 from the template to the variable size using post.
But i get the error mentioned which i believe is because name for the <select> is common in all the <option>.
If i can either get an alternate way to do that or solve this error both type of solutions are welcomed.
*I am not using Django Forms because i don't know how to have django form display like i am displaying my products in cart and on the product page.
ANSWER
I was missing a submit button and was rather using a <a href="{% url 'add_item' product.pk %}>Add To Cart</a>" to submit the form which was not working.
Now i replaced it with <button class="btn btn-success" style="margin-top: 10px;" type="submit">Add To Cart New</button>
And the form Action is given the link i was trying to go to.
<form method="post" enctype="multipart/form-data" action="{% url 'add_item' product.pk %}">
A silly mistake on my side.
Thanks for the answers.
Expanding on what #Yevhenii M. said, and talking particularly about the MultiValueDictKeyError:
This error happens when the given key (sizes in this case) is not found in the POST dict. This might be happening (i'm only guessing, since you didn't post the full html code), because you didn't put the corresponding <form> tag surrounding the select.
So, the final code would look something like:
<form action="url-to-send-form-data" method="POST">
{% csrf_token %}
<select name="sizes">
{% for size in product.sizes.all %}
<option value="{{size.nameSize}}">{{size.nameSize}}</option>
{% endfor %}
</select>
</form>
The {% csrf_token %} is needed in order to protect you against Cross Site Request Forgery attacks (more info: https://docs.djangoproject.com/en/2.2/ref/csrf/)
EDIT: Now that I take a closer look, the error message shows that the url is being called with a GET request (maybe because of trying to access to /item_added/1 straight from the browser's url). That is why django can't find the sizes key.
One common way to call the url via post, is as shown in the code snipet above, and adding a submit button to the html:
...
<button type="submit">Submit</button>
</form>
You don't need to use <ul> tag here.
You can write:
Select Size:
<select name="sizes">
{% for size in product.sizes.all %}
<option value="{{size.nameSize}}">{{size.nameSize}}</option>
{% endfor %}
</select>
and result will be the same.
Since you didn't specify that add_item(request, pk) works only by POST, then you can't expect that request.POST always will be presented.
Better write your code as this:
if request.POST:
# do something
And if you don't specify default value for your select in template, then sizeswill not be in your request.POST.
You can write like this just to be sure that you got some value:
request.POST.get('sizes', 'some_default_value')
Just because you get MultiValueDictKeyError you need to see what you get in request. Maybe you get QueryDict, then you need to extract first value. For example, see this SO question. For example, print your request.POST or check type.

Django-crispy-forms: set css for individual field and inputs

Is there a way to specify the css for an individual field and input in django crispy forms? I am using bootstrap4 and would like to use a horizontal form for a few fields in my form.
I know you can use a self.helper to set label.class and field.class but I presume that applies to all field. I only want to change the label and field class on a few of my fields.
EDIT:
I need to add css to the label that is different from the input
I'm trying to get a horizontal field inside a form like the amount field below
<div id="div_id_amount" class="row">
<label for="id_amount" class="col-form-label col-2 requiredField">
Amount<span class="asteriskField">*</span>
</label>
<div class="">
<input type="number" name="amount" step="0.01" class="numberinput form-control col-md" required="" id="id_amount">
</div>
</div>
One solution is given here:
You add the class attributes for the input field via the widget, as also explained in the django docs
You explicitly add the <label> tags with the correct class in your HTML.
Or, for the label, you can also create the following template filter:
#register.filter(is_safe=True)
def label_with_classes(field, css):
return field.label_tag(attrs={'class': css})
which you can use like this in your template after you've loaded it with {% load my_filters %}: {{ form.name|label_with_classes:"col-sm-6 col-lg-3" }}
I don't know of an easy way with crispy-forms.
You can add this in your Layout:
Field('password', id="password-field", css_class="passwordfields", title="Explanation")
You can find more details here

customise django widget in template

I have standard model form in django with Imagefield and standard widget. It made me such output on the page:
Currently: qwe/Tulips.jpg <input id="image-clear_id" name="image-clear" type="checkbox" /> <label for="image-clear_id">Clear</label><br />
Change: <input id="id_image" name="image" type="file" />
I want to place outputs of this widget in different parts of page. How can I cut it in templates.
If there is a way to use part of the output in template like {{form.name_of_field.label}} or {{form.name_of_field.errors}}
I've tried different names but no use
There must be a way to use them apart.
And yet another one who needs form styling.
I would recommend to use Widget Tweaks
<form method='POST' action="/" enctype='multipart/form-data'>
{% load widget_tweaks %}
{% csrf_token %}
{{ form.first_name |add_class:"customCSS1 customCSS2" }}
{{ form.second_name |add_class:"customCSS3 customCSS4" }}
</form>
{{ form.media.js }}
with this plugin you can style the form as you wish. All Css classes work. You can put each form field wherever you want on the Page. Is that what you are looking for? Your question is a bit misleading.
Hope that helps if not leave a comment :)

Plugin with editable link element

While implementing a Django CMS site, I’m a little stuck on link management (internal or external). In my project I have a specific box plugin the operator is to use quite often. I added screenshots of edit dialog and box rendering at the end of the question.
The edit dialog is nice, but right now the button is just a char field. So the link selection, either to a page within Django CMS or to an external URL, is missing. I looked for a link field, but until now I am lost.
How to add the feature to let the operator select an internal or external link ?
The plugin consists of these parts:
models.py
from django.db import models
from cms.models.pluginmodel import CMSPlugin
from djangocms_text_ckeditor.fields import HTMLField
class CardPlugin(CMSPlugin):
title = models.CharField(max_length=256,default='')
description = HTMLField(configuration='CKEDITOR_SETTINGS',
default='')
button = models.CharField(max_length=256,default='')
def __str__(self):
return str(self.title)
cms_plugins.py
class CardCMSPlugin(CMSPluginBase):
model = CardPlugin
name = 'Card'
render_template = "card-default.html"
card-default.html
{% load cms_tags %}
<section class="card card--primary-light">
<div class="card__inner">
<div class="card__content">
<div class="card__text">
<h2 class="card__title">
{{ instance.title }}
</h2>
<p class="card__description">
{{ instance.description }}
</p>
</div>
{% if instance.button %}
<div class="card__buttons">
{{ instance.button }}
</div>
{% endif %}
</div>
</div>
</section>
the rendered box
The plugin edit dialog looks like this:
I'd suggest looking at adding the djangocms-link plugin as a child plugin. It's a very good plugin to link to internal CMS pages or external addresses. That way you could drop the button field from your model, and instead render the child plugins in your template.
The docs on nested plugins would be a good read.
Your plugin definition would become something like this;
class ParentCMSPlugin(CMSPluginBase):
render_template = 'parent.html'
name = 'Parent'
model = ParentPlugin
allow_children = True
child_classes = ['LinkPlugin']
To render child plugins you'd then do this with your template;
{% load cms_tags %}
<section class="card card--primary-light">
<div class="card__inner">
<div class="card__content">
<div class="card__text">
<h2 class="card__title">
{{ instance.title }}
</h2>
<p class="card__description">
{{ instance.description }}
</p>
</div>
{% for plugin in instance.child_plugin_instances %}
{% render_plugin plugin %}
{% endfor %}
</div>
</div>
</section>
And that would use the default render template for the child plugin. If the default didn't match the styling etc, you could handle the rendering in the template instead of using render_plugin or subclass the LinkPlugin to work how you want, or extend it's attributes etc.
Some further consideration should do to dropping your description field in favour of also using the TextPlugin as a child, because the CMS text plugin can nest plugins within itself and is something I'd always use over an HTMLField.
Further still, if you're developing applications hooked in to CMS, take a look at PlaceholderFields which allow you to create placeholders in your own models to hold & use the CMS plugins that you can use in CMS pages. That gets really good for things like news apps or blog style content etc.

Django templates iterate through list of tuples and give them all buttons

I have a User model and the user's have university attribute. I want users to be able to scroll through a list of universities and choose one as a button, I don't want to have a dropdown selecter thing. So I passed in the UserInfo.UNIVERSITY_CHOICES (UserInfo is a one to one with the user model) to my template and try to iterate through it using:
<form method="get" action="/newUniversity/">
{% csrf_token %}
{% for school in universityList %}
<input class='submitbtn' type="submit" name="school" value="{{ school }}"></center>
{% endfor %}
</form>
However I get a bunch of buttons that say ('Harvard','Harvard') instead of just Harvard. I tried to index the tuple by doing school[1] but that gives me an error. Is there a way to do this or am I doing it a completely wrong way?
If UserInfo.UNIVERSITY_CHOICES is tuple (like the ones you would use with the django admin) you must choose which of the values you are after:
school.0
or
school.1
Notice Django's Template Language is not Python! You can see a reference of the language here:
https://docs.djangoproject.com/en/dev/topics/templates/