Getting Started with Python Django (5)

Child model CRUD

How to read a child

Let's display a list of child's impressions for the parent's book.

In cms / models.py, the impression defined the book as a foreign key.

class Impression(models.Model):
    """Impressions"""
    book = models.ForeignKey(Book, verbose_name='Books', related_name='impressions', on_delete=models.CASCADE)
    comment = models.TextField('comment', blank=True)

Therefore, the child's impressions associated with the book can be read out as follows using related_name. Again, I don't write SQL.

impressions = book.impressions.all().order_by('id')   #Read children's impressions of books

View of child list

This time, I will write using ListView of general view. With this, paging etc. can be easily realized.

Add the following description to cms / views.py.

from django.views.generic.list import ListView
  :

class ImpressionList(ListView):
    """List of impressions"""
    context_object_name='impressions'
    template_name='cms/impression_list.html'
    paginate_by = 2  #Page up to 2 pages per page

    def get(self, request, *args, **kwargs):
        book = get_object_or_404(Book, pk=kwargs['book_id'])  #Read parents' books
        impressions = book.impressions.all().order_by('id')   #Read children's impressions of books
        self.object_list = impressions
        
        context = self.get_context_data(object_list=self.object_list, book=book)    
        return self.render_to_response(context)

Child list template

Applying BootStrap,

I am doing that. It's a little long.

Create mybook / cms / templates / cms / impression_list.html by inheriting mybook / cms / templates / cms / base_html.

{% extends "cms/base.html" %}

{% block title %}List of impressions{% endblock title %}

{% block content %}
    <h4 class="mt-4 border-bottom">List of impressions<small class="text-muted ml-3">{{ book.name }}</small></h4>
    <a href="{% url 'cms:impression_add' book_id=book.id %}" class="btn btn-primary btn-sm my-3">add to</a>
    <table class="table table-striped table-bordered">
      <thead>
        <tr>
          <th>ID</th>
          <th>comment</th>
          <th>operation</th>
        </tr>
      </thead>
      <tbody>
        {% for impression in impressions %}
        <tr>
          <td>{{ impression.id }}</td>
          <td>{{ impression.comment|linebreaksbr }}</td>
          <td>
            <a href="{% url 'cms:impression_mod' book_id=book.id impression_id=impression.id %}" class="btn btn-outline-primary btn-sm">Fix</a>
            <button class="btn btn-outline-danger btn-sm del_confirm" data-toggle="modal" data-target="#deleteModal" data-pk="{{ impression.id }}" data-url="{% url 'cms:impression_del' book_id=book.id impression_id=impression.id %}">Delete</button>
          </td>
        </tr>
        {% endfor %}
      </tbody>
    </table>

    {% if is_paginated %}
    <nav aria-label="Page navigation">
      <ul class="pagination">
        {% if page_obj.has_previous %}
          <li class="page-item"><a class="page-link" href="?page={{ page_obj.previous_page_number }}" aria-label="Previous"><span aria-hidden="true">&laquo;</span><span class="sr-only">Previous</span></a></li>
        {% else %}
          <li class="page-item disabled"><a class="page-link" href="#" aria-label="Previous"><span aria-hidden="true">&laquo;</span><span class="sr-only">Previous</span></a></li>
        {% endif %}
        {% for linkpage in page_obj.paginator.page_range %}
          {% ifequal linkpage page_obj.number %}
            <li class="page-item active"><a class="page-link" href="#">{{ linkpage }}</a></li>
          {% else %}
            <li class="page-item"><a class="page-link" href="?page={{ linkpage }}">{{ linkpage }}</a></li>
        {% endifequal %}
        {% endfor %}
        {% if page_obj.has_next %}
          <li class="page-item"><a class="page-link" href="?page={{ page_obj.next_page_number }}" aria-label="Next"><span aria-hidden="true">&raquo;</span><span class="sr-only">Next</span></a></li>
        {% else %}
          <li class="page-item disabled"><a class="page-link" href="#" aria-label="Next"><span aria-hidden="true">&raquo;</span><span class="sr-only">Next</span></a></li>
        {% endif %}
      </ul>
    </nav>
    {% endif %}

    <a href="{% url 'cms:book_list' %}" class="btn btn-secondary btn-sm">Return</a>

    {#Modal dialog confirming deletion#}
    <div class="modal fade" id="deleteModal" tabindex="-1" role="dialog" aria-labelledby="deleteModalLabel" aria-hidden="true">
      <div class="modal-dialog" role="document">
        <div class="modal-content">
          <div class="modal-header">
            <h5 class="modal-title" id="deleteModalLabel">Verification</h5>
            <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
          </div>
          <div class="modal-body">
            <p>ID: <span id="del_pk"></span>Do you want to delete?</p>
          </div>
          <div class="modal-footer">
            <a href="#" class="btn btn-primary" id="del_url">OK</a>
            <button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
          </div>
        </div>
      </div>
    </div>
{% endblock content %}

{% block extra_js %}
<script>
$(function() {
  $('.del_confirm').on('click', function () {
     $("#del_pk").text($(this).data("pk"));
     $('#del_url').attr('href', $(this).data("url"));
  });
});
</script>
{% endblock %}

The completed list page will be as follows. (Still, it will not work unless you do the future, so please think of it as such an image)

django10.jpg

Add / modify child form

Add the following to cms / forms.py. Here we will create the underlying form for adding and modifying Impression models in cms / models.py.

  :
from cms.models import Book, Impression
  :

class ImpressionForm(ModelForm):
    """Impression form"""
    class Meta:
        model = Impression
        fields = ('comment', )

View of adding and modifying children

Add the following to cms / views.py.

  :
from cms.models import Book, Impression
from cms.forms import BookForm, ImpressionForm
  :

def impression_edit(request, book_id, impression_id=None):
    """Editing impressions"""
    book = get_object_or_404(Book, pk=book_id)  #Read parents' books
    if impression_id:   # impression_id is specified(At the time of correction)
        impression = get_object_or_404(Impression, pk=impression_id)
    else:               # impression_id not specified(At the time of addition)
        impression = Impression()

    if request.method == 'POST':
        form = ImpressionForm(request.POST, instance=impression)  #Create a form from POSTed request data
        if form.is_valid():    #Form validation
            impression = form.save(commit=False)
            impression.book = book  #Set the parent's book of this impression
            impression.save()
            return redirect('cms:impression_list', book_id=book_id)
    else:    #At the time of GET
        form = ImpressionForm(instance=impression)  #Create a form from an impression instance
        
    return render(request,
                  'cms/impression_edit.html',
                  dict(form=form, book_id=book_id, impression_id=impression_id))

Templates for adding and modifying children

Create mybook / cms / templates / cms / impression_edit.html by inheriting mybook / templates / base_html.

{% extends "cms/base.html" %}
{% load bootstrap4 %}

{% block title %}Editing impressions{% endblock title %}

{% block content %}
    <h4 class="mt-4 mb-5 border-bottom">Editing impressions</h4>
    {% if impression_id %}
    <form action="{% url 'cms:impression_mod' book_id=book_id impression_id=impression_id %}" method="post">
    {% else %}
    <form action="{% url 'cms:impression_add' book_id=book_id %}" method="post">
    {% endif %}
      {% csrf_token %}
      {% bootstrap_form form layout='horizontal' %}
      <div class="form-group row">
        <div class="offset-md-3 col-md-9">
          <button type="submit" class="btn btn-primary">Send</button>
        </div>
      </div>
    </form>
    <a href="{% url 'cms:impression_list' book_id=book_id %}" class="btn btn-secondary btn-sm">Return</a>
{% endblock content %}

The page for addition and modification is as follows. (Still, it will not work unless you do the future, so please think of it as such an image)

django11.jpg

View of child deletion

Add the following to cms / views.py.

This time, instead of erasing it suddenly, I'm displaying a modal dialog in Bootstrap and issuing a confirmation message. However, the contents of the view are the same as those of the parent's book.

def impression_del(request, book_id, impression_id):
    """Delete impressions"""
    impression = get_object_or_404(Impression, pk=impression_id)
    impression.delete()
    return redirect('cms:impression_list', book_id=book_id)

django12.jpg

Child url scheme

Add the following to cms / urls.py.

urlpatterns = [
    :

    #Impressions
    path('impression/<int:book_id>/', views.ImpressionList.as_view(), name='impression_list'),  #List
    path('impression/add/<int:book_id>/', views.impression_edit, name='impression_add'),        #Registration
    path('impression/mod/<int:book_id>/<int:impression_id>/', views.impression_edit, name='impression_mod'),  #Fix
    path('impression/del/<int:book_id>/<int:impression_id>/', views.impression_del, name='impression_del'),   #Delete
]

Modify parent list

Add a link so that you can get an "impression list" of the corresponding book from the list of parent books.

Add a line to mybook / cms / templates / cms / book_list.html.

          <td>
            <a href="{% url 'cms:book_mod' book_id=book.id %}" class="btn btn-outline-primary btn-sm">Fix</a>
            <a href="{% url 'cms:book_del' book_id=book.id %}" class="btn btn-outline-danger btn-sm">Delete</a>
            <a href="{% url 'cms:impression_list' book_id=book.id %}" class="btn btn-outline-info btn-sm">List of impressions</a>
          </td>

django13.jpg

Now, start the local server, follow the "List of impressions" from the "List of books", and register / modify / delete the impressions.

http://127.0.0.1:8000/cms/book/

If you can CRUD a model with a parent-child relationship as explained so far, the rest is how to design the model, so I think that you can apply it to make various things.

Continue to Introduction to Python Django (6).

Recommended Posts

Getting Started with Python Django (1)
Getting Started with Python Django (3)
Getting Started with Python Django (6)
Getting Started with Python Django (5)
Django 1.11 started with Python3.6
1.1 Getting Started with Python
Getting Started with Python
Getting Started with Django 1
Getting Started with Python
Getting Started with Django 2
Getting Started with Python Functions
Getting Started with Django with PyCharm
Python3 | Getting Started with numpy
Getting Started with Python responder v2
Getting Started with Python Web Applications
Getting Started with Python for PHPer-Classes
Getting Started with Python Basics of Python
Getting Started with Python Genetic Algorithms
Getting started with Python 3.8 on Windows
Getting Started with Python for PHPer-Functions
Getting Started with python3 # 1 Learn Basic Knowledge
Getting started with Android!
Getting Started with Golang 2
Getting Started with Python Web Scraping Practice
Getting started with apache2
Getting Started with Golang 1
Getting Started with Optimization
Getting Started with Python for PHPer-Super Basics
Getting Started with Python Web Scraping Practice
Getting started with Dynamo from Python boto
Getting Started with Golang 3
Getting started with Spark
Getting Started with Pydantic
Getting Started with Golang 4
Getting Started with Jython
Getting Started with Heroku-Viewing Hello World in Python Django with Raspberry PI 3
Getting started with Python with 100 knocks on language processing
[Translation] Getting Started with Rust for Python Programmers
Django Getting Started Part 2 with eclipse Plugin (PyDev)
Getting started with AWS IoT easily in Python
Django Getting Started Part 3 about Python3 & MySQL Connector
Materials to read when getting started with Python
Settings for getting started with MongoDB in python
Translate Getting Started With TensorFlow
Do Django with CodeStar (Python3.6.8, Django2.2.9)
Getting Started with Tkinter 2: Buttons
Get started with Django! ~ Tutorial ⑤ ~
Getting Started with PKI with Golang ―― 4
Django Getting Started: 2_ Project Creation
Django Getting Started: 1_Environment Building
Do Django with CodeStar (Python3.8, Django2.1.15)
Python3 + Django ~ Mac ~ with Apache
Django Getting Started: 4_MySQL Integration
Get started with Django! ~ Tutorial ④ ~
Get started with Django! ~ Tutorial ⑥ ~
Get started with Python! ~ ② Grammar ~
Getting Started with python3 # 2 Learn about types and variables
Getting Started with Google App Engine for Python & PHP
started python
Get started with Python! ~ ① Environment construction ~
Link to get started with python