If you have any mistakes or misunderstandings, please kindly point them out.
Django has a powerful template language.
It is the View that supplies the data to the template. And there's also a quick way to code it. That is the "Generic View".
It seems that long ago I used function-based generic views, but now I mainly use class-based views. The current Django Japanese translation docs are up to 1.4, but there are good docs for class-based generic views.
http://docs.djangoproject.jp/en/latest/topics/class-based-views.html
However, there were fewer articles explaining class-based generic views than I expected, so I decided to write them down.
--How to use class-based generic views in Django
The view is the controller in Rails. Django seems to call it view because it is based on the idea of MTV (Model, Template, View).
It is responsible for supplying the data to the template, but most websites
--List of specific conditions --Narrow down and display articles from DB --Display a single article
It has a function called. The process is pre-defined in Django so you don't have to write similar code over and over again.
They are called "generic views", "function-based generic views" if provided by a function, and "class-based generic views" if provided by a class.
In the general view, the appropriate default value is set according to the model, form, etc. Therefore, the advantage is that the amount written by the programmer is very small.
In this article, I've written down about "class-based generic views".
Class-based generic views define similar processing for each class. We can inherit from that class, modify class variables if needed, and override methods to insert our own processing.
** This is the first step, so let's focus on how to write it. ** **
Generic views are mainly used in views.py
etc.
Also, link the URL with the function ʻas_view () in ʻurls.py
.
Let's write a sample.
Suppose you created a project with django-admin
etc. and created one application as manager.py startapp foo
.
Well, I will write.
foo/views.py
from django.views.generic import TemplateView
class SampleTemplateView(TemplateView):
template_name = "index.html"
It is now ready for use. You can see that the amount of description is very small.
Here, TemplateView
is a generic view.
Views are prepared for each purpose in django.views.generic
etc., so ʻimport` and inherit.
URL is
urls.py
from foo.views import SampleTemplateView
urlpatterns = [
url(r'^sample$', SampleTemplateView.as_view()),
]
If so, SampleTemplateView
will handle it nicely when accessing / sample
.
In this way, you can drastically reduce the amount of code you write to views.py
.
As the name implies, TemplateView
is intended to be drawn using a template.
If you use another general-purpose view instead of TemplateView
, you can display the list without writing the code to get the data from the DB, or you can output the data after narrowing down by specific conditions.
In the first step, I could only view the template. However, you will usually want to display the data read from the DB.
In such a case, override the method defined in the generic view.
The method I often override is get_context_data
.
Use it as follows.
views.py
from django.views.generic import TemplateView
class SampleTemplate(TemplateView):
template_name = "index.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) #First call the inherited method
context["foo"] = "bar"
return context
Use like.
In the case of the above code, the template allows you to use a variable called foo
.
If you use {{foo}}
in the template, it will be bar
.
If the file name of the template is ʻindex.html` etc.
index.html
<div class="sample">{{ foo }}</div>
given that,
index.html
<div class="sample">bar</div>
It means that.
In other words, if you describe the process you want to insert in this method and put it in the return value of get_context_data
, you can use it in the template.
Override the method in this way and add the processing you need to the generic view. This is the basic usage.
There are many useful general-purpose views such as ListView
for displaying a list and DetailView
for creating individual pages, so I will introduce them.
** Note: Not all are presented here **
https://github.com/django/django/blob/master/django/views/generic/init.py
If you look at, many more generic views are defined, such as RedirectView
and FormView
.
TemplateView
As the name implies, TemplateView
is a general-purpose view that displays something by specifying a template.
Therefore, you must specify the template name.
Also, since it calls get_context_data
, it overrides and sets the necessary data.
Of course, it is out of the control of the general view, so you need to do the count and filtering yourself.
views.py
from django.views.generic import TemplateView
class MyTemplateView(TemplateView):
template_name = "index.html" #Mandatory
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
#Do various things
return context
The author mainly uses it on the top page of the site.
ListView
https://docs.djangoproject.com/ja/1.9/ref/class-based-views/generic-display/#listview
As the name suggests, ListView
is used when creating list pages.
If you simply create a list of target models,
views.py
from django.views.generic import ListView
from foo.model import MyModel
class MyListView(ListView):
model = MyModel
It is defined as.
model = MyModel
is the model that creates the list.
The template would look like this.
mymodel/mymodel_list.html
<ul>
{% for item in object_list %}
<li>{{ item }}</li>
{% endfor %}
</ul>
Even if there is a lot of data in the DB, ListView
will split the list by 10 by default </ s> (changed as pointed out in the comment) You can control the number of items output on one page with.
The number to divide is a variable called paginate_by
.
In other words, if you want to divide 5 cases at a time
views.py
class MyListView(ListView):
model = MyModel
paginate_by = 5
Is defined as.
This is a setting that if there are 100 data items, only 5 items will be displayed on one page.
Also, sometimes you may want to change the sort order of the data to be acquired in advance, or filter and control it.
In that case, override the get_queryset
method.
views.py
class MyListView(ListView):
model = MyModel
paginate_by = 5
def get_queryset(self):
return MyModel.objects.filter(some_column=foo)
To do.
Then it will issue the query defined by get_queryset
and store the data in ʻobject_list`.
If you want to limit the number of items to be extracted in the list, specify here.
The designation is a normal slice.
views.py
def get_queryset(self, queryset=None):
return MyModel.objects.all()[:10]
With this, even if there are 100 data items, only 10 items will be extracted.
This writing can be a little shorter.
views.py
class MyListView(ListView):
model = MyModel
paginate_by = 5
queryset = MyModel.objects.filter(some_column=foo)
Whichever you use, the result will not change.
If you want to issue queries dynamically, use the former, and if you always want the same result, use the latter.
Of course, you can pass data from other tables to the template by overriding the get_context_data
method.
views.py
class MyListView(ListView):
model = MyModel
paginate_by = 5
def get_queryset(self):
return MyModel.objects.filter(some_column=foo)
def get_context_data(self, **kwargs):
context = super().get_context_data(**data)
context["bar"] = OtherModel.objects.all() #Get data from other models
return context
However, in this case, ʻOtherModel is not under the control of the generic view, so
context ["bar"] stores the entire number of ʻOtherModel
.
DetailView
https://docs.djangoproject.com/ja/1.9/ref/class-based-views/generic-display/#detailview
As the name implies, DetailView
is a general-purpose view for individual detail pages.
Acquires data for a single row of records.
views.py
from django.views.generic import DetailView
from mymodel.model import MyModel
class MyDetailView(DetailView):
model = MyModel
URL is
urls.py
urlpatterns = [
url(r'^(?P<pk>\d+)$', MyDetailView.as_view()),
]
will do.
pk
is the primary key, but DetailView
uses this name to identify the record.
You can change it, but if you don't need it, you can leave it as it is.
https://docs.djangoproject.com/ja/1.9/ref/class-based-views/generic-editing/#django.views.generic.edit.CreateView
CreateView
is a view that provides a form to add a new record.
ʻUpdateView`, as you might expect, is a view that provides a form to update existing data.
views.py
from django.views.generic.edit import CreateView
class MyCreateView(CreateView):
model = MyModel
fields = ("name", ) #List or tuple
Define it like this. It's not much different from other generic views.
However, you need to define a variable called fields
in CreateView
and ʻUpdateView. This means that when data is entered from the form, it will be ignored except for the fields defined in
fields`.
Is it something like Rails' Strong Parameters?
What sets CreateView
and ʻUpdateViewapart from other generic views is that they" create a form ". That is, it creates a variable called
form instead of ʻobject
or ʻobject_list`.
The form
variable contains data for creating a form, making it easy to create a form.
Here's a template that uses the form
variable.
<form method="post">
{% csrf_token %}
<table>
{{ form }}
</table>
<input type="submit">
</form>
You have to write the HTML tag <form> </ form>
yourself, but the form fields will be generated for you.
{{form}}
outputs a field using a table by default.
If you want to make a field using the <p> </ p>
tag, use {{form.as_p}}
.
{% csrf_token%}
is a CSRF measure. Required if you've created a POST form with Django.
https://ja.wikipedia.org/wiki/%E3%82%AF%E3%83%AD%E3%82%B9%E3%82%B5%E3%82%A4%E3%83%88%E3%83%AA%E3%82%AF%E3%82%A8%E3%82%B9%E3%83%88%E3%83%95%E3%82%A9%E3%83%BC%E3%82%B8%E3%82%A7%E3%83%AA
http://docs.djangoproject.jp/en/latest/ref/contrib/csrf.html
You can also use form objects such as ModelForm
.
In this way, you can easily leverage your existing form classes.
forms.py
from django import forms
from myapp.model import MyModel
class MyModelForm(forms.ModelForm):
class Meta:
model = MyModel
fields = ("name", )
views.py
from forms import MyModelForm
class MyCreateView(CreateView):
form_class = MyModelForm
Validation is also an important feature of these forms. Even if you submit the form, if you get an error in validation and it is not added / updated, you may be confused if you do not notify the user.
Therefore, the methods form_valid
and form_invalid
are defined in these general-purpose views, and you can perform the necessary processing depending on whether the validation has passed or not.
For example, it's common to tell users if the form they submitted was saved successfully. At that time, Django uses the message framework.
http://docs.djangoproject.jp/en/latest/ref/contrib/messages.html
views.py
from django.views.generic.edit import CreateView
from django.contrib import messages #Message framework
from myapp.models import MyModel
class MyCreateView(CreateView):
model = MyModel
def form_valid(self, form):
'''When passed validation'''
messages.success(self.request, "Saved")
return super().form_valid(form)
def form_invalid(self, form):
'''When validation fails'''
message.warning(self.request, "Could not save")
return super().form_invalid(form)
Here, we have added our own messages to the form_valid
method, which is called when validation is successful, and the form_invalid
, which is called when validation is unsuccessful.
By doing this, you can add your own processing, so in addition to the above example, you can insert processing such as notifying the administrator by email when an error occurs.
When you're done with your own processing, call the inheriting method and return the return value.
By the way, to display the message, do as follows. The content of the document is as it is.
{% if messages %}
<ul class="messages">
{% for message in messages %}
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
DeleteView
As the name implies, DeleteView
deletes a record.
The template is (AppName) / (AppName) _confirm_delete.html
.
views.py
from django.views.generic.edit import DeleteView
from myapp.models import MyModel
class MyDeleteView(DeleteView):
model = MyModel
The template in this case will be a confirmation form, "Are you sure you want to delete it?"
Perhaps you don't really want to delete it, you just want to turn on the delete flag.
In such a case, it is better to override the delete
method.
However, I haven't tried it because I delete it obediently.
In addition to the above-mentioned processing, the class-based general-purpose view can freely override the template file name and variable name. In addition, the method is also common, so I will introduce some. I think it's usually best to use the default value and override it only when needed.
As you may have already noticed, generic views have some regularity.
Overriding get_context_data
, doing the necessary processing, and setting it in a variable was introduced in the first step.
If you want to pass data to a template, this should be enough.
So, on the contrary, when the generic view automatically retrieves the data, what variables are set in the data and what data is set in the data?
In the class-based general-purpose view, data is automatically acquired from the DB according to its purpose (inheriting class).
Set from which table to get the data like model = MyModel
.
views.py
class MyListView(ListView):
model = MyModel #Get a list of MyModels automatically
By doing this, you will get the data from MyModel
.
The result etc. is to be set in a variable with a fixed name.
ʻObject if there is only one record such as an individual page. If there is more than one, ʻobject_list
.
The template would look like this:
Individual pages etc.
{{ object }}
If there is more than one
{% for item in object_list %}
{{ item }}
{% endfor %}
However, I can't tell what this means by looking at the template.
You may want to make the variable name more descriptive.
In such a case, assign the variable name to context_object_name
.
views.py
class MyBookList(ListView):
model = Books
context_object_name = "my_books" #Specify the variable name on this line
This way, in the template
<ul>
{% for book in my_books %}
<li>{{ book.name }}</li>
{% endfor %}
</ul>
You can call it like this. Now that you know what the variable name refers to, it's easy to see what the variable means just by reading the template.
views is a controller. Therefore, pass the data to the appropriate template. The template can be specified explicitly, but it has a default template name. that is,
(ModelName)/(ModelName)_(ViewName).html
That is.
They are,
AppName
manage.py startapp
etc.ViewName
list
for ListView
and detail
for DetailView
It is supposed to be.
That is, using ListView
with myapp
will look for myapp / myapp_list.html
by default.
If you want to change this
views.py
class MyListView(ListView):
model = MyModel
template_name = "my_list_view.html" #Template specification on this line
To do.
If you are using a generic view, you will want to define the same variable in every view. For example, "site name". It's not good to define it in all views, so I wonder if I should create a common class and inherit it.
base_view.py
from django.views.generic import ListView
from myapp.models import MyModel
#Please inherit object without inheriting Mixin etc.
class MyCommonView(object):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["SITE_NAME"] = "SITE-NAME"
return context
class MyListView(ListView, MyCommonView):
model = MyModel
Now, if you want to change the site name, you only have to change it in one place ...? That would be one way, but I think it's better to use the Context Processor obediently.
I'm tired.
I hope it will be of some help to those who use Django.
For the time being
I have confirmed the operation with, but please kindly tell me if there is something wrong.
Recommended Posts