How can I set rich text editor inside Django Template without using crispy form {{form.media}}. I am not using crispy form right now. What to do.
I don't think there's any other method to do this. But, I can provide you the simplest solution.
Create a forms.py file inside your Django APP
from django.forms import ModelForm
from .models import Order
class OrderForm(ModelForm):
class Meta:
model = Order
fields = ['description']
Here, Order is your Model Name.
Inside your views.py
from django.shortcuts import render
from order.models import Order
from .forms import OrderForm
# Create your views here.
def post_order(request):
if request.method == "GET":
order_form = OrderForm()
required_dict = {
'form':order_form,
}
return render(request, "themes/order/order_post.html",required_dict)
Related
Django version 4.1
Aim: to render a form, using a custom FORM_RENDERER and a class-based FormView with custom context (extra_context={'svg': {'id_batch': 'number'}}).
Problem: custom context added is successfully added (via the get_context_data method) at one stage of the render, but is not passed to the custom form renderer. You can see in the image of stack trace below (of two sequential calls of the stack) that {'svg': {'id_batch': 'number'}} is present in one context variable, but not in the one passed to the FORM_RENDERER.
The same issue is present if I use a CreateView instead. Below are snippets of the relevant files:
# settings.py
# All of my forms are rendered with this same html snippet
from django.forms.renderers import TemplatesSetting
class CustomFormRenderer(TemplatesSetting):
form_template_name = "form_snippet.html"
FORM_RENDERER = "project.settings.CustomFormRenderer"
# forms.py
from django.forms import ModelForm
from .models import Upload
class UploadForm(ModelForm):
class Meta:
model = Upload
fields = ['batch']
# views.py
from django.views.generic import FormView
from .forms import UploadForm
class MeasurementView(FormView):
# default template will be 'assays/upload_form.html'
template_name = 'assays/upload_form.html'
form_class = UploadForm
extra_context = {'svg': {'id_batch': 'number'}}
I am currently using model formsets in my project.
The problem I find is that the app may have to show more than 50 forms on the same page, so saving them using the .save() method would generate more than 50 queries (one query for each form I'm going to save).
Since all forms have the same structure, it would be ideal to be able to save them with bulk_create, in such a way that only one query is generated, however the modelformset does not support bulk_create.
Is there any way to save all the answers of the forms with only one query?
The only thing that I can think of, is after validating the forms with formset.is_valid(), recover the request.POST and from there save with bulk_create.
Is there a better alternative?
I think you are very close to solution (But you can use form.cleaned_data also, not QueryDict). I will show you my implementation now (Which uses bulk_create() Manager/QuerySet method. This will help us to avoid a lot of hits on DB)
forms.py
class MyForm(forms.Form):
''' use same names for fields as you have in models.py '''
name = forms.CharField()
surname = forms.CharField()
models.py
class Person(models.Model):
name = models.CharField(max_length=55)
surname = models.CharField(max_length=55)
class Meta:
db_table = 'person'
views.py
from django.shortcuts import render
from django.http import JsonResponse
from django.forms import formset_factory
from django.db import connection
from .models import Person
from .forms import MyForm
N = 3 # number of forms
def index(request):
FormSet = formset_factory(MyForm, extra=N)
if request.method == 'POST':
fs = FormSet(data=request.POST)
if fs.is_valid():
data_for_bulk = [Person(**field_dict) for field_dict in fs.cleaned_data] # this returns list and pass to bulk_create() method.
Person.objects.bulk_create(data_for_bulk)
# use connection.queries to make monitoring of sql queries during HTTP POST request.
for query in connection.queries:
print(query['sql'], '\n')
return JsonResponse({'status_message': 'OK'})
else:
fs = FormSet()
return render(request, 'test.html', {'form': fs})
I hope, my solution will help you. Good luck !
AttributeError type object 'Data_Point ' has no attribute 'objects'plz check and correct me
AttributeError at /
type object 'myProduction' has no attribute 'objects'
model":
from django.db import models
from django.contrib.auth.models import User
class Production(models.Model):
title=models.CharField(max_length=120)
def __str__(self):
return self.title
My Form
from django import forms
from.models import Production
class myProduction(forms.ModelForm):
class Meta:
model=Production
fields =['title']
class Raw_Pro(forms.Form):
title = forms.CharField()
My View
from django.shortcuts import render
from .form import myProduction,Raw_Pro
def my_index(request):
my_form=Raw_Pro()
if request.method=='POST':
my_form=Raw_Pro(request.POST)
if my_form.is_valid():
myProduction.objects.create(my_form.cleaned_data)
else:
print(my_form.errors)
context={"form":my_form}
return render(request, "index.html",context)
You make some mistakes here:
myProduction here is your ModelForm (defined in forms.py), not your model (this is Production, defined in `models.py);
you here use Raw_Pro as form, which is not a ModelForm, which is likely not what you want to use;
in case of a successful form, you can use mymodelform.save() to create/edit the object; and
if the creation is successful, you should redirect to a page, for example the same page. By not doing so, a refresh of the user, would trigger a POST with the same parameters.
from django.shortcuts import render
from .form import myProduction
def my_index(request):
if request.method == 'POST':
my_form = myProduction(request.POST)
if my_form.is_valid():
my_form.save()
return redirect(my_index) # or somewhere else
else:
my_form = myProduction()
context = {"form":my_form}
return render(request, "index.html",context)
Note: as specified by PEP-8 [Python-doc], you should use camelcase starting with an Uppercase for class names. So you better rename your myProduction class to MyProduction, or much better ProductionForm, since then it is clear what that class is doing.
I am learning Django but cannot understand ModelForm ans models.Model, could anyone explain the difference between them? Thanks!
Adapted from django docs
A ModelForm is a Form that maps closely to the fields defined in a specific Model. Models are defined by subclassing models.Model.
A Model is the source of information about your data. It contains the essential fields and behaviours of the data you’re storing. Generally, each model maps to a single database table. When you are developing your webapp, chances are that you’ll have forms that map closely to Django models. For this reason, Django provides a helper class that lets you create a Form class from a Django model. This helper class is the ModelForm class
The ModelForms you create are rendered in your templates so that users can create or update the actual data that is stored in the database tables defined by your Models.
For instance lets say you want to store data about articles in your web application, you would first define a model called Article like so:
in your models.py:
from django.db import models
class Article(models.Model):
title = models.CharField(max_length=30)
body = models.TextField(max_length=300)
in your forms.py you would create a modelForm to correspond with the Article model you have just created.
from .models import Article
from django.forms import ModelForm
class ArticleForm(ModelForm):
class Meta:
model = Article
fields = ['title', 'body']
and then in your views.py you can render your articleform:
from django.shortcuts import render
from django.http import HttpResponseRedirect
from .forms import ArticleForm
def article_form_view(request):
# if this is a POST request we need to process the form data
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = ArticleForm(request.POST)
# check whether it's valid:
if form.is_valid():
# process the data in form.cleaned_data as required
# ...
# redirect to a new URL:
return HttpResponseRedirect('/')
# if a GET (or any other method) we'll create a blank form
else:
form = ArticleForm()
return render(request, 'article_form.html', {'form': form})
I would like to add some extra fields to pages in django-cms (in django admin panel). How do this in the simplest way?
Create a new app (called extended_cms or something) and in models.py create the following:
from django.db import models
from django.utils.translation import ugettext_lazy as _
from cms.models.pagemodel import Page
class ExtendedPage(models.Model):
page = models.ForeignKey(Page, unique=True, verbose_name=_("Page"), editable=False, related_name='extended_fields')
my_extra_field = models.CharField(...)
then create an admin.py:
from models import ExtendedPage
from cms.admin.pageadmin import PageAdmin
from cms.models.pagemodel import Page
from django.contrib import admin
class ExtendedPageAdmin(admin.StackedInline):
model = ExtendedPage
can_delete = False
PageAdmin.inlines.append(ExtendedPageAdmin)
try:
admin.site.unregister(Page)
except:
pass
admin.site.register(Page, PageAdmin)
which will add your extended model to as an inline to any page you create. The easiest way to access the extended model setttings, is to create a context processor:
from django.core.cache import cache
from django.contrib.sites.models import Site
from models import ExtendedPage
def extended_page_options(request):
cls = ExtendedPage
extended_page_options = None
try:
extended_page_options = request.current_page.extended_fields.all()[0]
except:
pass
return {
'extended_page_options' : extended_page_options,
}
and now you have access to your extra options for the current page using {{ extended_page_options.my_extra_field }} in your templates
Essentially what you are doing is creating a separate model with extra settings that is used as an inline for every CMS Page. I got this from a blog post previously so if I can find that I'll post it.
EDIT
Here is the blog post: http://ilian.i-n-i.org/extending-django-cms-page-model/
There is an official way to extend the page & title models, I highly recommend this official documentation:
Extending the page & title models from docs.django-cms.org
I also highly recommend using a placeholder if you can, since writing this answer, I now prefer creating a placeholder for the use case of cover images. (You can even get just the image URL in your template if you want to).
Summary of the link:
Create a subclass of PageExtension in your models.py file and register it:
class IconExtension(PageExtension):
image = models.ImageField(upload_to='icons')
extension_pool.register(IconExtension)
Create also a subclass of PageExtensionAdmin in your admin.py file and register it:
class IconExtensionAdmin(PageExtensionAdmin):
pass
admin.site.register(IconExtension, IconExtensionAdmin)
Finally, to make it accessible from the toolbar, create a subclass of ExtensionToolbar in cms_toolbars.py and register it:
#toolbar_pool.register
class IconExtensionToolbar(ExtensionToolbar):
model = IconExtension
def populate(self):
current_page_menu = self._setup_extension_toolbar()
if current_page_menu:
page_extension, url = self.get_page_extension_admin()
if url:
current_page_menu.add_modal_item(_('Page Icon'), url=url,
disabled=not self.toolbar.edit_mode)
The official documentation goes into more detail and explanation.
There is an open GitHub issue on adding support for adding elements to the normal and advanced "page settings" dialogues.
There's also a way to do this without using an inline, and having the fields anywhere on the Page form. For example, I have a custom setting for "color scheme" that I wanted to be under the "Basic Settings" fieldset. This can be done by overriding the ModelForm and the ModelAdmin's fieldsets. Also, I opted for a OneToOne field instead of a ForeignKey, for simplicity's sake.
models.py:
from django.db import models
from cms.models.pagemodel import Page
from django.conf import settings
class PageCustomSettings(models.Model):
page = models.OneToOneField(Page, editable=False,
related_name='custom_settings')
color_scheme = models.CharField(blank=True, choices=settings.COLOR_SCHEMES,
max_length=20)
admin.py:
from django import forms
from django.conf import settings
from django.contrib import admin
from cms.admin.pageadmin import PageAdmin, PageForm
from cms.models.pagemodel import Page
from web.models import PageCustomSettings
color_scheme_choices = (('', '---------'),) + settings.COLOR_SCHEMES
class CustomPageForm(PageForm):
color_scheme = forms.ChoiceField(choices=color_scheme_choices,
required=False)
def __init__(self, *args, **kwargs):
# make sure that when we're changing a current instance, to set the
# initial values for our custom fields
obj = kwargs.get('instance')
if obj:
try:
opts = obj.custom_settings
kwargs['initial'] = {
'color_scheme': opts.color_scheme
}
except PageCustomSettings.DoesNotExist:
pass
super(CustomPageForm, self).__init__(*args, **kwargs)
def save(self, commit=True):
# set the custom field values when saving the form
obj = super(CustomPageForm, self).save(commit)
try:
opts = PageCustomSettings.objects.get(page=obj)
except PageCustomSettings.DoesNotExist:
opts = PageCustomSettings(page=obj)
opts.color_scheme = self.cleaned_data['color_scheme']
opts.save()
return obj
PageAdmin.form = CustomPageForm
PageAdmin.fieldsets[1][1]['fields'] += ['color_scheme']
admin.site.unregister(Page)
admin.site.register(Page, PageAdmin)
I've got here via Google and the answers got me on the right track for Django CMS 3 Beta. To extend the page model and hook your extension into the toolbar, you can follow along the official documentation:
http://django-cms.readthedocs.org/en/latest/how_to/extending_page_title.html
Access value in template
{{ request.current_page.<your_model_class_name_in_lowercase>.<field_name> }}
For example, I extended the page model with this model:
from django.db import models
from cms.extensions import PageExtension
from cms.extensions.extension_pool import extension_pool
class ShowDefaultHeaderExtension(PageExtension):
show_header = models.BooleanField(default=True)
extension_pool.register(ShowDefaultHeaderExtension)
To access its values in the template:
{{ request.current_page.showdefaultheaderextension.show_header }}
Since I dont have enough reputation I cannot comment on Timmy O'Mahony's Post directly. However I want to note that the proposed solution of adding a StackedInline Object to the PageAdmin.inlines list does not work any more as supposed.
I'm working with Djangocms 3.3 and somewhere between Timmy O'Mahony's version any mine the authors changed the semantic of the inline List. It's content is now shown in the Permissions Menu for that specific page (including possibly added futher StackedInline or TabularInline items).