How can I style a django form with css? - python

I tried looking for the answer earlier but couldn't seem to figure out a few things. I'm creating my form in a form.py file so its a python file.
Here is my forms.py file :
class UploadForm(ModelForm):
name = forms.TextInput(attrs={'class': 'myfieldclass'})
details = forms.TextInput()
littype = forms.TextInput()
image = forms.ImageField()
class Meta:
model = info
fields = ["name", "details", "littype", "image"]
Here is my views.py function for it if it helps find the solution :
def uploadform(request):
if request.method == 'POST':
form = UploadForm(request.POST, request.FILES)
print(request.FILES)
if form.is_valid():
form.save()
redirect(home)
return render(request, 'uploadform.html', {'form': UploadForm})
To style it I thought I could do something like this which I found in another question :
class MyForm(forms.Form):
myfield = forms.CharField(widget=forms.TextInput(attrs={'class': 'myfieldclass'}))
Except I have no idea how to link a css page to that python file. This is what I tried writing but i think it doesnt work because its meant for html but its in a python file :
<link type="text/css" rel="stylesheet" href="templates/form.css">
And so I'm just not sure how to style my form. Thanks for any answers!

Within your template you have to just import the css file in the head tag, but do ensure you load static first.
html file:
{% load static %}
<!doctype html>
<html lang="en">
<head>
# import the css file here
<link rel="stylesheet" href="{% static 'path to css file' %}">
</head>
...
</html>
Within the css file:
# Styling the class
.myfieldclass{
width: 30% !important;
height: 100px !important;
...
}
But please note that you don't have to import a css file since you can add the style tag in the head tag as well. For example:
<!doctype html>
<html lang="en">
<head>
<style type="text/css">
.myfieldclass{
width: 30% !important;
height: 100px !important;
...
}
</style>
</head>
...
</html>
You could apply css from the python file itself as well.
Approach from the python file.
# Custom way to set css styling on a form field in python code
def field_style():
styles_string = ' '
# List of what you want to add to style the field
styles_list = [
'width: 30% !important;',
'height: 100px !important;',
]
# Converting the list to a string
styles_string = styles_string.join(styles_list)
# or
# styles_string = ' '.join(styles_list)
return styles_string
class MyForm(forms.Form):
myfield = forms.CharField(widget=forms.TextInput(attrs={'class': 'myfieldclass', 'style': field_style()}))
# 'style': field_style() .... field_style() will return in this case 'width: 30% !important; height: 100px !important;'
Any of those should work but I do recommend doing the styling from the hmtl or css file instead.

class StocksForm(forms.Form):
stocks = forms.CharField(
label="",
widget=forms.TextInput(
attrs={
"class": "special",
"size": "40",
"label": "comment",
"placeholder": "Comma Seperated eg - Reliance, Steel, Acrysil.. ",
}
),
)
Template side
{% load static %}
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<link rel="stylesheet" type="text/css" href="{% static '/css/cards.css' %}">
the stylesheet has got CSS
as
.special{
font-variant: small-caps;
}
This is how django will render the form with the class, and the styling class will be taken from stylesheet
Hope this helps! :)

You can just include the CSS in the template header like any other stylesheet
Thanks

My standard template uses Django block structure so I can group page-specific CSS with its page.
{% extends "base.html" %}
{% block content %}
my html ...
{% endblock %}
{% block extracss %}
{{block.super}}
<style>
... page-specific CSS
</style>
{% endblock %}
Base.html contains an empty block definition
{% block extracss %}{% endblock %}
which serves to locate the block with other site-wide CSS.

Related

How to add custom CSS for form labels to Django forms?

I have a django form for which I need to increase the font size of the labels. Based on this StackOverflow discussion, what I need to do is add a CSS class and apply it to the control-label. How do I actually go about doing that?
My form is populated like so:
class MyForm(forms.Form):
def __init__(self, *args, **kwargs):
super(MyForm, self).__init__(*args, **kwargs)
fields_to_add = {
# many fields here, but all in this format. Removed for brevity.
'purchase_order_number': forms.ChoiceField(
label="Purchase Order",
choices=purchase_order_numbers),
}
self.fields.update(fields_to_add)
self = add_classes(self)
The add_classes code is as follows:
def add_classes(self):
"""Add styling to form inputs."""
for key, value in self.fields.items():
self.fields[key].widget.attrs.update(
{'class': 'form-control', # <- this is what I expect to change
'style': 'font-size: large',}
)
return(self)
I assume I need to modify add_classes to add some form of control-label or a custom class like {'class': 'form-control control-label',, but once I do that, where do I actually specify the size of my labels? They are not specified in my HTML template.
Edit: based on the suggestion, I have created a file named customFormStyle.css with the following contents:
.form-control {
height: 50px;
background-color: red;
}
and in the HTML of my form have included a link to that CSS:
<link rel="stylesheet" type="text/css" href="/main/static/main/css/customFormStyle.css"/>
...but my form does not reflect the change.
Here is my template, for context ({{form}} is where the form is passed in, I do not have direct access to the HTML for the fields):
{% extends "main/_one_column.html" %}
{% comment %} {% load crispy_forms_tags %} {% endcomment %}
{% block maincontent %}
<link href="https://cdn.jsdelivr.net/npm/select2#4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
<link rel="stylesheet" type="text/css" href="/main/static/main/css/customFormStyle.css"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/select2#4.1.0-rc.0/dist/js/select2.min.js"></script>
<form action="" method="POST" class="form" enctype="multipart/form-data">
{% csrf_token %}
{{ form}}
<input class="btn btn-primary" type="submit" value="Save">
</form>
{% endblock %}
You must add a custom class to your field, then you must add a css style, it can be from a file or directly in your html.
In this case, the class is 'form-control', so the following style would suffice
<style>
.form-control {
height: 50px;
}
</style>

Select objects from django model based on user input

I have a large django model with about 800 objects and I want to create a view in which the user can select a certain number of those objects to pass to another view for further processing. The fact that there are so many objects of the model makes listing all the objects very unpractical, as the user would have to scroll through 800 objects.
In order to address this problem, I want to place an as-you-type search-bar in the top of the view so that the user can type the name of the objects and select them by clicking them. When the objects are selected, they should appear under the search-bar as tags that the user can remove by clicking an "x" next to each one.
When the user has made all the required selections, then they should be able to click a button and jump to the next view where those selected objects are accessible.
The model I am using can be simplified to:
class Song():
song_name = models.CharField(max_length=256)
song_author = models.CharField(max_length=256, blank=True)
song_content = models.TextField()
def __str__(self):
return self.song_name
class Meta:
ordering = ['song_order']
song_order = models.PositiveIntegerField(editable=False, db_index=True)
So far I have been able to make a view to search through the model.
mytemplate.html
<!DOCTYPE html>
{% load static %}
<html style="height: 100%;" lang="en">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<link rel="preload" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Material+Icons" as="style" onload="this.rel='stylesheet'">
<link rel="preload" href="https://unpkg.com/bootstrap-material-design#4.1.1/dist/css/bootstrap-material-design.min.css" as="style" onload="this.rel='stylesheet'">
<link rel="stylesheet" href="{% static 'css/main.css' %}">
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"></script>
</head>
<body>
{% block body_block %}
<div class="container" style="padding-bottom:40px;margin-top: 35px;">
<div class="form-group">
<label for="searchInput" class="bmd-label-floating">Search</label>
<input type="text" class="form-control" id="searchInput" oninput="filter()">
</div>
<ul class="list-group bmd-list-group-sm">
{% for song in songs %}
<div
class="list-group-item"
data-title="{{song.song_name}}"
data-author="{{song.song_author}}"
data-lyrics="{{song.song_content}}">
<h4>
{{song.song_name}}
{% if song.song_author %}
({{ song.song_author }})
{% endif %}
</h4>
</div>
{% endfor %}
</ul>
</div>
<script>
$('#searchInput').focus();
function short(s) {
let punctuationRegEx = /[.,\/#!$%\^&\*;:{}=\-_`~()]/g;
return s.replace(punctuationRegEx, '')
.toLowerCase()
.normalize("NFD")
.replace(/[\u0300-\u036f]/g, "");
}
function filter() {
let f = short($('#searchInput').val());
$('.list-group-item').each(function (index) {
if (short($(this).data('title') + "").includes(f) ||
short($(this).data('author') + "").includes(f)
) {
$(this).show();
} else {
$(this).hide();
}
});
}
</script>
{% endblock %}
</body>
</html>
views.py
class SongListView(ListView):
context_object_name = 'songs'
model = Song
template_name = "songapp/mytemplate.html"
Any ideas on how to do the selection?
I have created a part inventory program with the as you type search.
It's a complete example of ajax call for search and database.
You can modify it to show the results under the search with the X.
https://github.com/edcodes/Django-Parts-Inventory

'QuerySet' object has no attribute 'META' 500(internal server erro)

I'm trying to practice ajax in django but I got this error 'QuerySet' object has no attribute 'META'. But it's showing the data in the traceback but not in the template because of the error.How to fix this?
models.py
from django.db import models
# Create your models here.
class Profile(models.Model):
name = models.CharField(max_length=100)
email = models.CharField(max_length=100)
bio = models.CharField(max_length=100)
def __str__(self):
return self.name
I think it has something to do with the views but I cant figure it out.
views.py
from django.shortcuts import render
from .models import Profile
from django.http import JsonResponse
# Create your views here.
def list(request):
return render(request, 'livedata/list.html')
def getProfiles(request):
profiles = Profile.objects.all()
# print(JsonResponse({"profiles": list(profiles.values())}))
return JsonResponse({"profiles": list(profiles.values())})
urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.list, name='list'),
path('getProfiles', views.getProfiles, name='getProfiles')
]
index.html
{% load static %}
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
{% comment %} <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script> {% endcomment %}
<script src="https://code.jquery.com/jquery-3.5.1.js" integrity="sha256-QWo7LDvxbWT2tbbQ97B53yJnYU3WhH/C8ycbRAkjPDc=" crossorigin="anonymous"></script>
<script src="{% static 'js/main.js' %}" defer></script>
<title>Hello, world!</title>
</head>
<body>
{% block contents %}{% endblock contents %}
{% block scripts %}{% endblock scripts %}
<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
{% comment %} <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script> {% endcomment %}
{% comment %} <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script> {% endcomment %}
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>
</body>
</html>
list.html
{% extends 'livedata/index.html' %}
{% block contents %}
<h1>List of live data</h1>
<ul id="display">
</ul>
{% endblock contents %}
{% block scripts %}
<script>
$(document).ready(function () {
setInterval(function () {
$.ajax({
type: 'GET',
url: "{% url 'getProfiles' %}",
success: function (response) {
// console.log(response);
$("#display").empty();
for (var key in response.profiles) {
var temp = "<li>" + response.profiles[key].name + "</li>";
$("#display").append(temp);
}
},
error: function (response) {
alert("Error occured");
}
});
}, 1000);
});
</script>
{% endblock scripts %}
You should not name a view list, list is a builtin function that you use in other views. By defining a view named list, the list(profiles.values()) will call the view with profile.values() as the request.
Rename list to view_list for example and update the url patterns to direct to view_list instead:
def view_list(request):
return render(request, 'livedata/list.html')
def getProfiles(request):
profiles = Profile.objects.all()
# does not refer to the view &downarrow; but to the list builtin
return JsonResponse({"profiles": list(profiles.values())})
The urls.py thus looks like:
from django.urls import path
from . import views
urlpatterns = [
path('', views.view_list, name='list'),
path('getProfiles', views.getProfiles, name='getProfiles')
]

Write contents of ace.js editor to file in Django

I am playing around with the idea of editing my Django templates from the server. I know this is a far shot from that but I wrote this bit of code:
def editor(request):
handle=open(os.path.join(settings.BASE_DIR, 'app/code/test.html'), 'r+')
var=handle.read()
context = {
"message": "editor",
"code": var
}
return render(request, 'app/editor.html', context)
That reads a file and passes it's contents to the template where ace.js displays it in the editor.
<div id="editor-container">
<div id="editor">{{code}}</div>
</div>
It displays just fine and I can edit the text, but if I wanted to save my edits, writing them to the file, the button would need to go to a save route because I'm not using ajax, but how would I pass the new version of the document to the view to be written to the file?
To make this work you need to have an hidden input. Whenever the contents of the editor are updated, the input is also update. Saving the contents is just now a matter of submitting the form. Here is what I came up with.
First is the html template where the editor is.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Ace editing</title>
<style type="text/css" media="screen">
#editor {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
.editor-container {
position: relative;
height: 300px;
width: 100%;
}
</style>
</head>
<body>
<div class="editor-container">
<div id="editor">
{{code}}
</div>
</div>
<form method="POST">
{% csrf_token %} {{form.as_p}}
<button type="submit">Save</button>
</form>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.12/ace.js"></script>
<script>
var editor = ace.edit('editor');
editor.setTheme("ace/theme/monokai");
editor.session.setMode("ace/mode/html");
editor.on('change', function() {
code_hidden_input = document.querySelector('#id_code');
code_hidden_input.value = editor.getValue();
console.log(editor.getValue())
})
</script>
</body>
</html>
Now in your views.py the code will be like the following.
from django.shortcuts import render
from .forms import MyForm
import os
from django.conf import settings
# Create your views here.
def index(request):
form = MyForm()
handle = open(os.path.join(settings.BASE_DIR, 'core/templates/core/test.html'))
code = handle.read()
if request.method == "POST":
form = MyForm(request.POST)
if form.is_valid():
print(form.cleaned_data['code'])
# This is the part where you save the code you have
# edited to some file
context = {
'form': MyForm(),
'code': code
}
return render(request, "core/index.html", context)
In your forms.py file create a class called My Form like below
from django import forms
class MyForm(forms.Form):
code = forms.CharField(max_length=10000, widget=forms.HiddenInput())
That's all, note when submiting html using forms you need to sanitize your input.

How to combine two differente templates in one common app in django?

I want to create different templates, but both of them share almost the same attributes. For example, both the blog page and the movie page have the model 'Post' that allows users to add new Articles/Movies to the Website.
Also, I assume that the 'Movie - Post' model would need different fields than the 'Article - Post' model, but they still share many of them.
Someone can help me how to implement that out?
There are two possible ways to do this.
1. Make an outer file and insert all your code into the inner file. This uses extends.
The outer file, base.html
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href = "https://code.jquery.com/ui/1.10.4/themes/ui-lightness/jquery-ui.css"
rel = "stylesheet">
</head>
<body>
<p> You can also put anything else you want on every page here.</p>
<main role="main" class="container">
{% block content %}
{% endblock %}
</main>
</div>
</body>
</html>
The inner file, page.html
{% extends 'base.html' %}
{% block content %}
<p>This is the stuff you want to be unique to the page. </p>
{% endblock %}
The disadvantage of this method is that you are essentially putting one page inside another and it is a little less flexible.
2. Include the chunk of code inside an HTML file. This uses include.
The page you want to add the header to, page.html
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href = "https://code.jquery.com/ui/1.10.4/themes/ui-lightness/jquery-ui.css"
rel = "stylesheet">
</head>
<style>
body { padding-top: 70px;
font-family: Poppins;
}
</style>
<body>
{% include "header.html" %}
<main role="main" class="container">
<p> Whatever you want on your page</p>
</main>
</div>
</body>
</html>
The actual code for your header, header.html
<div class="header">
<p>My supercool header</p>
</div>
Include will insert that block of HTML code right where you put the include statement.
With regard to the models with common elements, you can do something like this:
from django.db import models
class CommonInfo(models.Model):
#common fields go here
post = models.CharField(max_length=100)
class Meta:
abstract = True
class Blog(CommonInfo):
#fields unique to blog go here
name = models.CharField(max_length=5)
class Movie(CommonInfo):
#fields unique to movie go here
name = models.CharField(max_length=5)

Categories

Resources