What's the difference between Django ModelForm and models.Model? - django

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})

Related

Django rich text editor inside django template not for Admin

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)

Is there any way to use bulk_create with model formsets?

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 !

HTTP forward from generic CreateView in Django?

I have a CreateView for a patient object (simplified):
from django.views.generic.edit import CreateView
import models
class PatientCreate(CreateView):
model = models.Patient
fields = ['name', 'country', ..]
# template_name is "patient_form.html" from CreateView
(I have overridden form_valid and get_context_data to set a few things by default, see for example here, but I think that's irrelevant.)
If a patient by the same name already exists, I'd like to simply HTTP forward to the detail page for that patient instead of creating a new one.
How do I do that?
I'm using Django 1.11.
You can add this logic in form_valid override. For example:
def form_valid(self, form):
name = form.cleaned_data.get('name')
your_model_objects = YourModel.objects.filter(name=name)
if your_model_objects.exists(): # lazy query, won't hit the database
obj = your_model_objects.first() # as entry exists, fetch the first object
return redirect(reverse('detail-url', args=[obj.pk])
else:
return super(YourClass, self).form_valid(form)

insert form data into tables in django

I am newbie in Django and wanted to know a very basic thing:
I have a form which has some dropdown boxes and textfields and upon hitting the button on the form, I want the data to be inserted into database table.
I have already created the table using model.py but dont know where the insert code would come.
The usual way to go about is to create a ModelForm if the data you are collecting is mapping to a model. You place the ModelForm in forms.py inside your app.
# forms.py
from django import forms
from someapp.models import SomeModel
class SomeForm(forms.ModelForm):
class Meta:
model=SomeModel
# views.py
from someapp.forms import SomeForm
def create_foo(request):
if request.method == 'POST':
form = SomeForm(request.POST)
if form.is_valid():
# form.save() saves the model to the database
# form.save does only work on modelforms, not on regular forms
form.save()
..... return some http response and stuff here ....
Read more here:
Forms and ModelForms.

How to efficiently initial data in Django forms.Form?

For example I have a Article model for blog articles so it's easy to add articles to the database.
But when I need to edit them, in form if I create a form class by form.ModelForm, I can pass instace=artcile to the form and that's it.
But if I create a form class by form.Forms I have to declare a form instance and pass fields to the form one by one.
Something like this
form = ArticleForm({
'title': article.title,
'body': article.body,
'pub_date': article.pub_date
'status': article.status,
'author': article.author,
'comments': article.comments.count(),
'blah': article.blahblah,
'againBlah': article.againBlah,
.....
})
It's ugly, isn't?
Is there any way to do this shorter, without using form.ModelForm?
You can use the model_to_dict and fields_for_model utils from django.forms.models:
# assuming article is an instance of your Article model:
from django.forms import Form
from django.forms.models import fields_for_model, model_to_dict
form = Form(model_to_dict(article))
form.fields.update(fields_for_model(article))
If you have an m2m relation, you can create a formset for it:
from django import forms
from django.forms.models import model_to_dict, fields_for_model
from django.forms.formsets import formset_factory
# assuming your related model is called 'Tag'
class TagForm(forms.Form):
def __init__(self, *args, **kwargs):
super(TagForm, self).__init__(*args, **kwargs)
self.fields.update(fields_for_model(Tag))
TagFormSet = formset_factory(TagForm)
formset = TagFormSet(initial=[model_to_dict(tag) for tag in article.tags.all()])
Then you can iterate through the formset to access the forms created for the related models:
for form in formset.forms:
print form