├── .gitignore
├── README.md
├── apps
├── apps
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── books_pc_formset
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── forms.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ └── __init__.py
│ ├── models.py
│ ├── templates
│ │ └── books_pc_formset
│ │ │ ├── book_confirm_delete.html
│ │ │ ├── book_form.html
│ │ │ ├── home.html
│ │ │ └── nav.html
│ ├── tests.py
│ ├── urls.py
│ └── views.py
├── books_pc_formset2
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── forms.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ └── __init__.py
│ ├── models.py
│ ├── templates
│ │ └── books_pc_formset2
│ │ │ ├── book_confirm_delete.html
│ │ │ ├── book_form.html
│ │ │ ├── home.html
│ │ │ ├── nav.html
│ │ │ ├── person_confirm_delete.html
│ │ │ └── person_form.html
│ ├── tests.py
│ ├── urls.py
│ └── views.py
├── books_pc_multi_view
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── forms.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ └── __init__.py
│ ├── models.py
│ ├── templates
│ │ └── books_pc_multi_view
│ │ │ ├── book_confirm_delete.html
│ │ │ ├── book_form.html
│ │ │ ├── book_view.html
│ │ │ ├── home.html
│ │ │ ├── nav.html
│ │ │ ├── review_confirm_delete.html
│ │ │ └── review_form.html
│ ├── tests.py
│ ├── urls.py
│ └── views.py
├── books_pc_multi_view2
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── forms.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ └── __init__.py
│ ├── models.py
│ ├── templates
│ │ └── books_pc_multi_view2
│ │ │ ├── book_confirm_delete.html
│ │ │ ├── book_form.html
│ │ │ ├── book_view.html
│ │ │ ├── home.html
│ │ │ ├── nav.html
│ │ │ ├── person_confirm_delete.html
│ │ │ ├── person_form.html
│ │ │ ├── review_confirm_delete.html
│ │ │ └── review_form.html
│ ├── tests.py
│ ├── urls.py
│ └── views.py
├── books_simple
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── forms.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ └── __init__.py
│ ├── models.py
│ ├── templates
│ │ └── books_simple
│ │ │ ├── book_confirm_delete.html
│ │ │ ├── book_form.html
│ │ │ ├── home.html
│ │ │ └── nav.html
│ ├── tests.py
│ ├── urls.py
│ └── views.py
├── manage.py
└── theme
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── migrations
│ └── __init__.py
│ ├── models.py
│ ├── static
│ └── css
│ │ └── style.css
│ ├── templates
│ ├── base.html
│ └── home.html
│ ├── tests.py
│ └── views.py
├── requirements.txt
└── www
├── media
└── .gitignore
└── static
└── .gitignore
/.gitignore:
--------------------------------------------------------------------------------
1 | db.sqlite3
2 | *.pyc
3 | __pycache__
4 | *.swp
5 | venv
6 | .vscode/
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # Django CRUD Parent/Child Example
3 |
4 | This project consist of five stand alone applications that shows different
5 | ways to implement CRUD operations in single table, and parent/child tables
6 | using Django web framework.
7 |
8 | This version uses Django 2.2 LTS version.
9 |
10 | ## Sample Applications
11 |
12 | The applications are:
13 |
14 | - books_simple: Single table CRUD operations.
15 | - books\_pc\_formset: Parent/Child CRUD operation using Django formsets, which means editing the children in the sample form as the parent.
16 | - books\_pc\_formset2: similar to previous app but uses a foreign key in the children.
17 | - books\_pc\_multiview: Parent/Child CRUD operation using multiple one view for the parent and another seperate view for the children.
18 | - books\_pc\_multiview2: similar to previous app but uses a foreign key in the children.
19 |
20 | ## Installation and Running
21 |
22 | Summary:
23 |
24 | git clone git@github.com:rayed/django-crud-parent-child.git
25 | cd django-crud-parent-child
26 | python3 -m venv venv
27 | . venv/bin/activate
28 | pip install -r requirements.txt
29 | cd apps
30 | ./manage.py migrate
31 | ./manage.py runserver
32 |
33 | ./manage.py createsuperuser
34 |
35 | Description of the installation steps:
36 |
37 | # Clone the project
38 | git clone git@github.com:rayed/django-crud-parent-child.git
39 |
40 | cd django-crud-parent-child
41 |
42 | # Create Python 3 virtual environment
43 | python3 -m venv venv
44 | # Activate the virtual environment
45 | . venv/bin/activate
46 |
47 | # Install required packages (Django 2.2 LTS)
48 | pip install -r requirements.txt
49 |
50 | cd apps
51 | # Create database tables for the project, project configured to use SQLite DB
52 | ./manage.py migrate
53 |
54 | # Run the development server
55 | ./manage.py runserver
56 |
57 |
--------------------------------------------------------------------------------
/apps/apps/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rayed/django-crud-parent-child/982f70f1ad762fca52500de09555371f1bcba8ac/apps/apps/__init__.py
--------------------------------------------------------------------------------
/apps/apps/settings.py:
--------------------------------------------------------------------------------
1 | """
2 | Django settings for apps project.
3 |
4 | Generated by 'django-admin startproject' using Django 2.2.13.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/2.2/topics/settings/
8 |
9 | For the full list of settings and their values, see
10 | https://docs.djangoproject.com/en/2.2/ref/settings/
11 | """
12 |
13 | import os
14 |
15 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
16 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
17 |
18 |
19 | # Quick-start development settings - unsuitable for production
20 | # See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/
21 |
22 | # SECURITY WARNING: keep the secret key used in production secret!
23 | SECRET_KEY = '408jjoy!o)hen3g&ew6g2#du$ql#6m8l(_m0vkr8n=m#u$7k)y'
24 |
25 | # SECURITY WARNING: don't run with debug turned on in production!
26 | DEBUG = True
27 |
28 | ALLOWED_HOSTS = []
29 |
30 |
31 | # Application definition
32 |
33 | INSTALLED_APPS = [
34 | 'theme.apps.ThemeConfig',
35 | 'books_simple.apps.BooksSimpleConfig',
36 | 'books_pc_formset.apps.BooksPcFormsetConfig',
37 | 'books_pc_formset2.apps.BooksPcFormset2Config',
38 | 'books_pc_multi_view.apps.BooksPcMultiViewConfig',
39 | 'books_pc_multi_view2.apps.BooksPcMultiView2Config',
40 | 'django.contrib.admin',
41 | 'django.contrib.auth',
42 | 'django.contrib.contenttypes',
43 | 'django.contrib.sessions',
44 | 'django.contrib.messages',
45 | 'django.contrib.staticfiles',
46 | ]
47 |
48 | MIDDLEWARE = [
49 | 'django.middleware.security.SecurityMiddleware',
50 | 'django.contrib.sessions.middleware.SessionMiddleware',
51 | 'django.middleware.common.CommonMiddleware',
52 | 'django.middleware.csrf.CsrfViewMiddleware',
53 | 'django.contrib.auth.middleware.AuthenticationMiddleware',
54 | 'django.contrib.messages.middleware.MessageMiddleware',
55 | 'django.middleware.clickjacking.XFrameOptionsMiddleware',
56 | ]
57 |
58 | ROOT_URLCONF = 'apps.urls'
59 |
60 | TEMPLATES = [
61 | {
62 | 'BACKEND': 'django.template.backends.django.DjangoTemplates',
63 | 'DIRS': [],
64 | 'APP_DIRS': True,
65 | 'OPTIONS': {
66 | 'context_processors': [
67 | 'django.template.context_processors.debug',
68 | 'django.template.context_processors.request',
69 | 'django.contrib.auth.context_processors.auth',
70 | 'django.contrib.messages.context_processors.messages',
71 | ],
72 | },
73 | },
74 | ]
75 |
76 | WSGI_APPLICATION = 'apps.wsgi.application'
77 |
78 |
79 | # Database
80 | # https://docs.djangoproject.com/en/2.2/ref/settings/#databases
81 |
82 | DATABASES = {
83 | 'default': {
84 | 'ENGINE': 'django.db.backends.sqlite3',
85 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
86 | }
87 | }
88 |
89 |
90 | # Password validation
91 | # https://docs.djangoproject.com/en/2.2/ref/settings/#auth-password-validators
92 |
93 | AUTH_PASSWORD_VALIDATORS = [
94 | {
95 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
96 | },
97 | {
98 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
99 | },
100 | {
101 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
102 | },
103 | {
104 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
105 | },
106 | ]
107 |
108 |
109 | # Internationalization
110 | # https://docs.djangoproject.com/en/2.2/topics/i18n/
111 |
112 | LANGUAGE_CODE = 'en-us'
113 |
114 | TIME_ZONE = 'UTC'
115 |
116 | USE_I18N = True
117 |
118 | USE_L10N = True
119 |
120 | USE_TZ = True
121 |
122 |
123 | # Static files (CSS, JavaScript, Images)
124 | # https://docs.djangoproject.com/en/2.2/howto/static-files/
125 |
126 | STATIC_URL = '/static/'
127 |
128 | DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
--------------------------------------------------------------------------------
/apps/apps/urls.py:
--------------------------------------------------------------------------------
1 | """apps URL Configuration
2 |
3 | The `urlpatterns` list routes URLs to views. For more information please see:
4 | https://docs.djangoproject.com/en/2.2/topics/http/urls/
5 | Examples:
6 | Function views
7 | 1. Add an import: from my_app import views
8 | 2. Add a URL to urlpatterns: path('', views.home, name='home')
9 | Class-based views
10 | 1. Add an import: from other_app.views import Home
11 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
12 | Including another URLconf
13 | 1. Import the include() function: from django.urls import include, path
14 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
15 | """
16 | from django.contrib import admin
17 | from django.urls import path, include
18 |
19 | import theme.views
20 |
21 | urlpatterns = [
22 | path('admin/', admin.site.urls),
23 |
24 | path('', theme.views.home, name='home'),
25 | path('books_simple/', include('books_simple.urls')),
26 | path('books_pc_formset/', include('books_pc_formset.urls')),
27 | path('books_pc_formset2/', include('books_pc_formset2.urls')),
28 | path('books_pc_multi_view/', include('books_pc_multi_view.urls')),
29 | path('books_pc_multi_view2/', include('books_pc_multi_view2.urls')),
30 | ]
31 |
--------------------------------------------------------------------------------
/apps/apps/wsgi.py:
--------------------------------------------------------------------------------
1 | """
2 | WSGI config for apps project.
3 |
4 | It exposes the WSGI callable as a module-level variable named ``application``.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/2.2/howto/deployment/wsgi/
8 | """
9 |
10 | import os
11 |
12 | from django.core.wsgi import get_wsgi_application
13 |
14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'apps.settings')
15 |
16 | application = get_wsgi_application()
17 |
--------------------------------------------------------------------------------
/apps/books_pc_formset/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rayed/django-crud-parent-child/982f70f1ad762fca52500de09555371f1bcba8ac/apps/books_pc_formset/__init__.py
--------------------------------------------------------------------------------
/apps/books_pc_formset/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 | from books_pc_formset.models import Book, Tag
3 |
4 |
5 | class TagInline(admin.TabularInline):
6 | model = Tag
7 |
8 | class BookAdmin(admin.ModelAdmin):
9 | inlines = [
10 | TagInline,
11 | ]
12 |
13 | admin.site.register(Book, BookAdmin)
--------------------------------------------------------------------------------
/apps/books_pc_formset/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class BooksPcFormsetConfig(AppConfig):
5 | name = 'books_pc_formset'
6 |
--------------------------------------------------------------------------------
/apps/books_pc_formset/forms.py:
--------------------------------------------------------------------------------
1 | from django.forms import ModelForm
2 |
3 | from .models import Book
4 |
5 | class BookForm(ModelForm):
6 | class Meta:
7 | model = Book
8 | fields = ['name', 'pages']
--------------------------------------------------------------------------------
/apps/books_pc_formset/migrations/0001_initial.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.13 on 2020-06-25 16:03
2 |
3 | from django.db import migrations, models
4 | import django.db.models.deletion
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | initial = True
10 |
11 | dependencies = [
12 | ]
13 |
14 | operations = [
15 | migrations.CreateModel(
16 | name='Book',
17 | fields=[
18 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
19 | ('name', models.CharField(max_length=200)),
20 | ('pages', models.IntegerField()),
21 | ],
22 | ),
23 | migrations.CreateModel(
24 | name='Tag',
25 | fields=[
26 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
27 | ('name', models.CharField(max_length=200)),
28 | ('weight', models.IntegerField()),
29 | ('book', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='books_pc_formset.Book')),
30 | ],
31 | ),
32 | ]
33 |
--------------------------------------------------------------------------------
/apps/books_pc_formset/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rayed/django-crud-parent-child/982f70f1ad762fca52500de09555371f1bcba8ac/apps/books_pc_formset/migrations/__init__.py
--------------------------------------------------------------------------------
/apps/books_pc_formset/models.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 |
3 | class Book(models.Model):
4 | name = models.CharField(max_length=200)
5 | pages = models.IntegerField()
6 |
7 | def __str__(self):
8 | return self.name
9 |
10 |
11 | class Tag(models.Model):
12 | book = models.ForeignKey(Book, on_delete=models.CASCADE)
13 | name = models.CharField(max_length=200)
14 | weight = models.IntegerField()
15 |
16 | def __str__(self):
17 | return self.name
18 |
19 |
--------------------------------------------------------------------------------
/apps/books_pc_formset/templates/books_pc_formset/book_confirm_delete.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block content %}
4 | {% include "books_pc_formset/nav.html" with book=book title="Delete" %}
5 |
6 |
10 |
11 | {% endblock %}
12 |
--------------------------------------------------------------------------------
/apps/books_pc_formset/templates/books_pc_formset/book_form.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block content %}
4 | {% include "books_pc_formset/nav.html" with book=book title="Edit" %}
5 |
6 |
14 |
15 | {% endblock %}
16 |
--------------------------------------------------------------------------------
/apps/books_pc_formset/templates/books_pc_formset/home.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block content %}
4 | {% include "books_pc_formset/nav.html" %}
5 |
6 | Books Parent/Child Formset
7 |
8 |
9 | {% for book in books %}
10 | - {{ book.name }} ({{ book.pages }} Pages)
11 | edit
12 | delete
13 |
14 | {% endfor %}
15 |
16 |
17 | New
18 |
19 | {% endblock %}
20 |
--------------------------------------------------------------------------------
/apps/books_pc_formset/templates/books_pc_formset/nav.html:
--------------------------------------------------------------------------------
1 |
2 | Application Home
3 | {% if book %}
4 | > {{ book }}
5 | {% endif %}
6 | {% if title %}
7 | > {{ title }}
8 | {% endif %}
9 |
--------------------------------------------------------------------------------
/apps/books_pc_formset/tests.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 |
3 | # Create your tests here.
4 |
--------------------------------------------------------------------------------
/apps/books_pc_formset/urls.py:
--------------------------------------------------------------------------------
1 | from django.urls import path
2 |
3 | from . import views
4 |
5 | app_name = 'books_pc_formset'
6 |
7 | urlpatterns = [
8 | path('', views.home, name='home'),
9 | path('new/', views.book_create, name='book_new'),
10 | path('edit//', views.book_update, name='book_edit'),
11 | path('delete//', views.book_delete, name='book_delete'),
12 | ]
13 |
--------------------------------------------------------------------------------
/apps/books_pc_formset/views.py:
--------------------------------------------------------------------------------
1 | from django.shortcuts import render, redirect, get_object_or_404
2 | from django.forms.models import inlineformset_factory
3 |
4 | from .models import Book, Tag
5 | from .forms import BookForm
6 |
7 |
8 | def home(request, template_name='books_pc_formset/home.html'):
9 | books = Book.objects.all()
10 | ctx = {
11 | 'books': books,
12 | }
13 | return render(request, template_name, ctx)
14 |
15 | def book_create(request, template_name='books_pc_formset/book_form.html'):
16 | InlineFormSet = inlineformset_factory(Book, Tag, fields=('name', 'weight'))
17 | form = BookForm(request.POST or None)
18 | formset = InlineFormSet(request.POST or None, instance=Book())
19 | if form.is_valid() and formset.is_valid():
20 | book = form.save()
21 | formset.instance = book
22 | formset.save()
23 | return redirect('books_pc_formset:home')
24 | ctx = {
25 | 'form': form,
26 | 'formset': formset,
27 | }
28 | return render(request, template_name, ctx)
29 |
30 | def book_update(request, pk, template_name='books_pc_formset/book_form.html'):
31 | InlineFormSet = inlineformset_factory(Book, Tag, fields=('name', 'weight'))
32 | book = get_object_or_404(Book, pk=pk)
33 | form = BookForm(request.POST or None, instance=book)
34 | formset = InlineFormSet(request.POST or None, instance=book)
35 | if form.is_valid() and formset.is_valid():
36 | book = form.save()
37 | formset.instance = book
38 | formset.save()
39 | return redirect('books_pc_formset:home')
40 | ctx = {
41 | 'form': form,
42 | 'formset': formset,
43 | }
44 | return render(request, template_name, ctx)
45 |
46 | def book_delete(request, pk, template_name='books_pc_formset/book_confirm_delete.html'):
47 | book = get_object_or_404(Book, pk=pk)
48 | if request.method=='POST':
49 | book.delete()
50 | return redirect('books_pc_formset:home')
51 | ctx = {
52 | 'book': book,
53 | }
54 | return render(request, template_name, ctx)
55 |
--------------------------------------------------------------------------------
/apps/books_pc_formset2/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rayed/django-crud-parent-child/982f70f1ad762fca52500de09555371f1bcba8ac/apps/books_pc_formset2/__init__.py
--------------------------------------------------------------------------------
/apps/books_pc_formset2/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 | from books_pc_formset2.models import Book, Person, Contributor
3 |
4 |
5 | class ContributorInline(admin.TabularInline):
6 | model = Contributor
7 |
8 | class BookAdmin(admin.ModelAdmin):
9 | inlines = [
10 | ContributorInline,
11 | ]
12 |
13 | admin.site.register(Book, BookAdmin)
14 | admin.site.register(Person)
15 |
--------------------------------------------------------------------------------
/apps/books_pc_formset2/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class BooksPcFormset2Config(AppConfig):
5 | name = 'books_pc_formset2'
6 |
--------------------------------------------------------------------------------
/apps/books_pc_formset2/forms.py:
--------------------------------------------------------------------------------
1 | from django.forms import ModelForm
2 |
3 | from .models import Book, Person
4 |
5 | class BookForm(ModelForm):
6 | class Meta:
7 | model = Book
8 | fields = ['name', 'pages']
9 |
10 | class PersonForm(ModelForm):
11 | class Meta:
12 | model = Person
13 | fields = ['name', 'email']
--------------------------------------------------------------------------------
/apps/books_pc_formset2/migrations/0001_initial.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.13 on 2020-06-25 16:03
2 |
3 | from django.db import migrations, models
4 | import django.db.models.deletion
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | initial = True
10 |
11 | dependencies = [
12 | ]
13 |
14 | operations = [
15 | migrations.CreateModel(
16 | name='Book',
17 | fields=[
18 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
19 | ('name', models.CharField(max_length=200)),
20 | ('pages', models.IntegerField()),
21 | ],
22 | ),
23 | migrations.CreateModel(
24 | name='Person',
25 | fields=[
26 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
27 | ('name', models.CharField(max_length=200)),
28 | ('email', models.EmailField(max_length=254)),
29 | ],
30 | ),
31 | migrations.CreateModel(
32 | name='Contributor',
33 | fields=[
34 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
35 | ('contribution', models.IntegerField(choices=[(1, 'Author'), (2, 'Editor'), (3, 'Reviewer')])),
36 | ('book', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='books_pc_formset2.Book')),
37 | ('person', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='books_pc_formset2.Person')),
38 | ],
39 | ),
40 | ]
41 |
--------------------------------------------------------------------------------
/apps/books_pc_formset2/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rayed/django-crud-parent-child/982f70f1ad762fca52500de09555371f1bcba8ac/apps/books_pc_formset2/migrations/__init__.py
--------------------------------------------------------------------------------
/apps/books_pc_formset2/models.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 |
3 | class Person(models.Model):
4 | name = models.CharField(max_length=200)
5 | email = models.EmailField()
6 |
7 | def __str__(self):
8 | return self.name
9 |
10 |
11 | class Book(models.Model):
12 | name = models.CharField(max_length=200)
13 | pages = models.IntegerField()
14 |
15 | def __str__(self):
16 | return self.name
17 |
18 |
19 | class Contributor(models.Model):
20 | AUTHOR = 1
21 | EDITOR = 2
22 | REVIEWER = 3
23 | CONTRIBUTION_CHOICES = (
24 | (AUTHOR, "Author"),
25 | (EDITOR, "Editor"),
26 | (REVIEWER, "Reviewer"),
27 | )
28 | book = models.ForeignKey(Book,on_delete=models.CASCADE)
29 | person = models.ForeignKey(Person,on_delete=models.CASCADE)
30 | contribution = models.IntegerField(choices=CONTRIBUTION_CHOICES)
31 |
32 | def __str__(self):
33 | return "%s %s" % (self.contribution, self.person)
34 |
35 |
--------------------------------------------------------------------------------
/apps/books_pc_formset2/templates/books_pc_formset2/book_confirm_delete.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block content %}
4 | {% include "books_pc_formset2/nav.html" with book=book title="Delete" %}
5 |
6 |
10 |
11 | {% endblock %}
12 |
--------------------------------------------------------------------------------
/apps/books_pc_formset2/templates/books_pc_formset2/book_form.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block content %}
4 | {% include "books_pc_formset2/nav.html" with book=book title="Edit Book" %}
5 |
6 |
14 |
15 | {% endblock %}
16 |
--------------------------------------------------------------------------------
/apps/books_pc_formset2/templates/books_pc_formset2/home.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block content %}
4 | {% include "books_pc_formset2/nav.html" %}
5 |
6 | Books Parent/Child Formset2
7 |
8 |
9 | People
10 |
11 | {% for person in persons %}
12 | - {{ person.name }} ({{ person.email }})
13 | edit
14 | delete
15 |
16 | {% endfor %}
17 |
18 |
19 | New
20 |
21 |
22 | Books
23 |
24 | {% for book in books %}
25 | - {{ book.name }} ({{ book.pages }} Pages)
26 | edit
27 | delete
28 |
29 | {% endfor %}
30 |
31 |
32 | New
33 |
34 | {% endblock %}
35 |
--------------------------------------------------------------------------------
/apps/books_pc_formset2/templates/books_pc_formset2/nav.html:
--------------------------------------------------------------------------------
1 |
2 | Application Home
3 | {% if book %}
4 | > {{ book }}
5 | {% endif %}
6 | {% if title %}
7 | > {{ title }}
8 | {% endif %}
9 |
--------------------------------------------------------------------------------
/apps/books_pc_formset2/templates/books_pc_formset2/person_confirm_delete.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block content %}
4 | {% include "books_pc_formset2/nav.html" with person=person title="Delete" %}
5 |
6 |
10 |
11 | {% endblock %}
12 |
--------------------------------------------------------------------------------
/apps/books_pc_formset2/templates/books_pc_formset2/person_form.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block content %}
4 | {% include "books_pc_formset2/nav.html" with person=person title="Edit Person" %}
5 |
6 |
10 |
11 | {% endblock %}
12 |
--------------------------------------------------------------------------------
/apps/books_pc_formset2/tests.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 |
3 | # Create your tests here.
4 |
--------------------------------------------------------------------------------
/apps/books_pc_formset2/urls.py:
--------------------------------------------------------------------------------
1 | from django.urls import path
2 |
3 | from . import views
4 |
5 | app_name = 'books_pc_formset2'
6 |
7 | urlpatterns = [
8 | path('', views.home, name='home'),
9 |
10 | path('person_new', views.person_create, name='person_new'),
11 | path('person_edit/', views.person_update, name='person_edit'),
12 | path('person_delete/', views.person_delete, name='person_delete'),
13 |
14 | path('book_new', views.book_create, name='book_new'),
15 | path('book_edit/', views.book_update, name='book_edit'),
16 | path('book_delete/', views.book_delete, name='book_delete'),
17 | ]
18 |
--------------------------------------------------------------------------------
/apps/books_pc_formset2/views.py:
--------------------------------------------------------------------------------
1 | from django.shortcuts import render, redirect, get_object_or_404
2 | from django.forms.models import inlineformset_factory
3 |
4 | from .models import Book, Contributor, Person
5 | from .forms import BookForm, PersonForm
6 |
7 |
8 |
9 | # ============ Home ===============
10 |
11 | def home(request, template_name='books_pc_formset2/home.html'):
12 | books = Book.objects.all()
13 | persons = Person.objects.all()
14 | ctx = {
15 | 'books': books,
16 | 'persons': persons,
17 | }
18 | return render(request, template_name, ctx)
19 |
20 |
21 | # ============ Book CRUD ===============
22 |
23 | def book_create(request, template_name='books_pc_formset2/book_form.html'):
24 | InlineFormSet = inlineformset_factory(Book, Contributor, fields=('person', 'contribution'))
25 | form = BookForm(request.POST or None)
26 | formset = InlineFormSet(request.POST or None, instance=Book())
27 | if form.is_valid() and formset.is_valid():
28 | book = form.save()
29 | formset.instance = book
30 | formset.save()
31 | return redirect('books_pc_formset2:home')
32 | ctx = {
33 | 'form': form,
34 | 'formset': formset,
35 | }
36 | return render(request, template_name, ctx)
37 |
38 | def book_update(request, pk, template_name='books_pc_formset2/book_form.html'):
39 | InlineFormSet = inlineformset_factory(Book, Contributor, fields=('person', 'contribution'))
40 | book= get_object_or_404(Book, pk=pk)
41 | form = BookForm(request.POST or None, instance=book)
42 | formset = InlineFormSet(request.POST or None, instance=book)
43 | if form.is_valid() and formset.is_valid():
44 | book = form.save()
45 | formset.instance = book
46 | formset.save()
47 | return redirect('books_pc_formset2:home')
48 | ctx = {
49 | 'form': form,
50 | 'formset': formset,
51 | }
52 | return render(request, template_name, ctx)
53 |
54 | def book_delete(request, pk, template_name='books_pc_formset2/book_confirm_delete.html'):
55 | book= get_object_or_404(Book, pk=pk)
56 | if request.method=='POST':
57 | book.delete()
58 | return redirect('books_pc_formset2:home')
59 | ctx = {
60 | 'book': book,
61 | }
62 | return render(request, template_name, ctx)
63 |
64 |
65 | # ============ Person CRUD ===============
66 |
67 | def person_create(request, template_name='books_pc_formset2/person_form.html'):
68 | form = PersonForm(request.POST or None)
69 | if form.is_valid():
70 | form.save()
71 | return redirect('books_pc_formset2:home')
72 | ctx = {
73 | 'form': form,
74 | }
75 | return render(request, template_name, ctx)
76 |
77 | def person_update(request, pk, template_name='books_pc_formset2/person_form.html'):
78 | person = get_object_or_404(Person, pk=pk)
79 | form = PersonForm(request.POST or None, instance=person)
80 | if form.is_valid():
81 | form.save()
82 | return redirect('books_pc_formset2:home')
83 | ctx = {
84 | 'form': form,
85 | }
86 | return render(request, template_name, ctx)
87 |
88 | def person_delete(request, pk, template_name='books_pc_formset2/person_confirm_delete.html'):
89 | person= get_object_or_404(Person, pk=pk)
90 | if request.method=='POST':
91 | person.delete()
92 | return redirect('books_pc_formset2:home')
93 | ctx = {
94 | 'person': person,
95 | }
96 | return render(request, template_name, ctx)
97 |
--------------------------------------------------------------------------------
/apps/books_pc_multi_view/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rayed/django-crud-parent-child/982f70f1ad762fca52500de09555371f1bcba8ac/apps/books_pc_multi_view/__init__.py
--------------------------------------------------------------------------------
/apps/books_pc_multi_view/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 | from books_pc_multi_view.models import Book, Review
3 |
4 | admin.site.register(Book)
5 | admin.site.register(Review)
--------------------------------------------------------------------------------
/apps/books_pc_multi_view/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class BooksPcMultiViewConfig(AppConfig):
5 | name = 'books_pc_multi_view'
6 |
--------------------------------------------------------------------------------
/apps/books_pc_multi_view/forms.py:
--------------------------------------------------------------------------------
1 | from django.forms import ModelForm
2 |
3 | from .models import Book, Review
4 |
5 | class BookForm(ModelForm):
6 | class Meta:
7 | model = Book
8 | fields = ['name', 'pages']
9 |
10 | class ReviewForm(ModelForm):
11 | class Meta:
12 | model = Review
13 | fields = ['name', 'review']
--------------------------------------------------------------------------------
/apps/books_pc_multi_view/migrations/0001_initial.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.13 on 2020-06-25 16:03
2 |
3 | from django.db import migrations, models
4 | import django.db.models.deletion
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | initial = True
10 |
11 | dependencies = [
12 | ]
13 |
14 | operations = [
15 | migrations.CreateModel(
16 | name='Book',
17 | fields=[
18 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
19 | ('name', models.CharField(max_length=200)),
20 | ('pages', models.IntegerField()),
21 | ],
22 | ),
23 | migrations.CreateModel(
24 | name='Review',
25 | fields=[
26 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
27 | ('name', models.CharField(max_length=200)),
28 | ('review', models.TextField()),
29 | ('book', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='books_pc_multi_view.Book')),
30 | ],
31 | ),
32 | ]
33 |
--------------------------------------------------------------------------------
/apps/books_pc_multi_view/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rayed/django-crud-parent-child/982f70f1ad762fca52500de09555371f1bcba8ac/apps/books_pc_multi_view/migrations/__init__.py
--------------------------------------------------------------------------------
/apps/books_pc_multi_view/models.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 |
3 |
4 | class Book(models.Model):
5 | name = models.CharField(max_length=200)
6 | pages = models.IntegerField()
7 |
8 | def __str__(self):
9 | return self.name
10 |
11 |
12 | class Review(models.Model):
13 | book = models.ForeignKey(Book,on_delete=models.CASCADE)
14 | name = models.CharField(max_length=200)
15 | review = models.TextField()
16 |
17 | def __str__(self):
18 | return "Review from: " + self.name
19 |
--------------------------------------------------------------------------------
/apps/books_pc_multi_view/templates/books_pc_multi_view/book_confirm_delete.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block content %}
4 | {% include "books_pc_multi_view/nav.html" with book=book title="Delete" %}
5 |
6 |
10 | {% endblock %}
11 |
--------------------------------------------------------------------------------
/apps/books_pc_multi_view/templates/books_pc_multi_view/book_form.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 |
4 | {% block content %}
5 | {% include "books_pc_multi_view/nav.html" with book=book title="Edit" %}
6 |
10 | {% endblock %}
11 |
--------------------------------------------------------------------------------
/apps/books_pc_multi_view/templates/books_pc_multi_view/book_view.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 |
4 | {% block content %}
5 | {% include "books_pc_multi_view/nav.html" with book=book title="View" %}
6 |
7 | Pages: {{ book.pages }}
8 |
9 | Reviews
10 |
11 | {% for review in reviews %}
12 | -
13 | {{ review.name }}
14 | {{ review.review|linebreaks }}
15 |
16 | edit
17 | delete
18 |
19 | {% endfor %}
20 |
21 |
22 | New Review
23 | {% endblock %}
24 |
--------------------------------------------------------------------------------
/apps/books_pc_multi_view/templates/books_pc_multi_view/home.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block title %}Book List{% endblock %}
4 |
5 | {% block content %}
6 | {% include "books_pc_multi_view/nav.html" %}
7 |
8 | Books Parent/Child with Multi View
9 |
10 |
11 | {% for book in books %}
12 | - {{ book.name }} ({{ book.pages }} Pages)
13 | view
14 | edit
15 | delete
16 |
17 | {% endfor %}
18 |
19 |
20 | New
21 | {% endblock %}
22 |
--------------------------------------------------------------------------------
/apps/books_pc_multi_view/templates/books_pc_multi_view/nav.html:
--------------------------------------------------------------------------------
1 |
2 | Application Home
3 | {% if book %}
4 | > {{ book.name }}
5 | {% endif %}
6 | {% if title %}
7 | > {{ title }}
8 | {% endif %}
9 |
--------------------------------------------------------------------------------
/apps/books_pc_multi_view/templates/books_pc_multi_view/review_confirm_delete.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 |
4 | {% block content %}
5 | {% include "books_pc_multi_view/nav.html" with book=book title="Delete Review" %}
6 |
10 | {% endblock %}
11 |
--------------------------------------------------------------------------------
/apps/books_pc_multi_view/templates/books_pc_multi_view/review_form.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 |
4 | {% block content %}
5 | {% include "books_pc_multi_view/nav.html" with book=book title="Edit Review" %}
6 |
10 | {% endblock %}
11 |
--------------------------------------------------------------------------------
/apps/books_pc_multi_view/tests.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 |
3 | # Create your tests here.
4 |
--------------------------------------------------------------------------------
/apps/books_pc_multi_view/urls.py:
--------------------------------------------------------------------------------
1 | from django.urls import path
2 |
3 | from . import views
4 |
5 | app_name = 'books_pc_multi_view'
6 |
7 | urlpatterns = [
8 | path('', views.home, name='home'),
9 |
10 | path('book_view//', views.book_view, name='book_view'),
11 | path('book_new', views.book_create, name='book_new'),
12 | path('book_edit//', views.book_update, name='book_edit'),
13 | path('book_delete//', views.book_delete, name='book_delete'),
14 |
15 | path('review_new//', views.review_create, name='review_new'),
16 | path('review_edit//', views.review_update, name='review_edit'),
17 | path('review_delete//', views.review_delete, name='review_delete'),
18 | ]
19 |
--------------------------------------------------------------------------------
/apps/books_pc_multi_view/views.py:
--------------------------------------------------------------------------------
1 | from django.shortcuts import render, redirect, get_object_or_404
2 | from django.forms import ModelForm
3 |
4 | from .models import Book, Review
5 | from .forms import BookForm, ReviewForm
6 |
7 |
8 | # ========== Home =========
9 |
10 | def home(request, template_name='books_pc_multi_view/home.html'):
11 | books = Book.objects.all()
12 | ctx = {
13 | 'books': books,
14 | }
15 | return render(request, template_name, ctx)
16 |
17 |
18 | # ========== Book CRUD =========
19 |
20 | def book_view(request, pk, template_name='books_pc_multi_view/book_view.html'):
21 | book= get_object_or_404(Book, pk=pk)
22 | reviews = Review.objects.filter(book=book)
23 | ctx = {
24 | 'book': book,
25 | 'reviews': reviews,
26 | }
27 | return render(request, template_name, ctx)
28 |
29 | def book_create(request, template_name='books_pc_multi_view/book_form.html'):
30 | form = BookForm(request.POST or None)
31 | if form.is_valid():
32 | form.save()
33 | return redirect('books_pc_multi_view:home')
34 | ctx = {
35 | 'form': form,
36 | }
37 | return render(request, template_name, ctx)
38 |
39 | def book_update(request, pk, template_name='books_pc_multi_view/book_form.html'):
40 | book= get_object_or_404(Book, pk=pk)
41 | form = BookForm(request.POST or None, instance=book)
42 | if form.is_valid():
43 | form.save()
44 | return redirect('books_pc_multi_view:home')
45 | ctx = {
46 | 'form': form,
47 | 'book': book,
48 | }
49 | return render(request, template_name, ctx)
50 |
51 | def book_delete(request, pk, template_name='books_pc_multi_view/book_confirm_delete.html'):
52 | book= get_object_or_404(Book, pk=pk)
53 | if request.method=='POST':
54 | book.delete()
55 | return redirect('books_pc_multi_view:home')
56 | ctx = {
57 | 'object': book,
58 | 'book': book,
59 | }
60 | return render(request, template_name, ctx)
61 |
62 |
63 | # ========== Review CRUD =========
64 |
65 | def review_create(request, parent_pk, template_name='books_pc_multi_view/review_form.html'):
66 | book = get_object_or_404(Book, pk=parent_pk)
67 | form = ReviewForm(request.POST or None)
68 | if form.is_valid():
69 | review = form.save(commit=False)
70 | review.book = book
71 | review.save()
72 | return redirect('books_pc_multi_view:book_view', parent_pk)
73 | ctx = {
74 | 'form': form,
75 | 'book': book,
76 | }
77 | return render(request, template_name, ctx)
78 |
79 | def review_update(request, pk, template_name='books_pc_multi_view/review_form.html'):
80 | review = get_object_or_404(Review, pk=pk)
81 | parent_pk = review.book.pk
82 | form = ReviewForm(request.POST or None, instance=review)
83 | if form.is_valid():
84 | form.save()
85 | return redirect('books_pc_multi_view:book_view', parent_pk)
86 | ctx = {
87 | 'form': form,
88 | 'book': review.book,
89 | }
90 | return render(request, template_name, ctx)
91 |
92 | def review_delete(request, pk, template_name='books_pc_multi_view/review_confirm_delete.html'):
93 | review = get_object_or_404(Review, pk=pk)
94 | parent_pk = review.book.pk
95 | if request.method=='POST':
96 | review.delete()
97 | return redirect('books_pc_multi_view:book_view', parent_pk)
98 | ctx = {
99 | 'object': review,
100 | 'book': review.book,
101 | }
102 | return render(request, template_name, ctx)
103 |
--------------------------------------------------------------------------------
/apps/books_pc_multi_view2/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rayed/django-crud-parent-child/982f70f1ad762fca52500de09555371f1bcba8ac/apps/books_pc_multi_view2/__init__.py
--------------------------------------------------------------------------------
/apps/books_pc_multi_view2/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 | from books_pc_multi_view2.models import Person,Book, Review
3 |
4 | admin.site.register(Person)
5 | admin.site.register(Book)
6 | admin.site.register(Review)
7 |
--------------------------------------------------------------------------------
/apps/books_pc_multi_view2/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class BooksPcMultiView2Config(AppConfig):
5 | name = 'books_pc_multi_view2'
6 |
--------------------------------------------------------------------------------
/apps/books_pc_multi_view2/forms.py:
--------------------------------------------------------------------------------
1 | from django.forms import ModelForm
2 |
3 | from .models import Person, Book, Review
4 |
5 | class PersonForm(ModelForm):
6 | class Meta:
7 | model = Person
8 | fields = ['name', 'email']
9 |
10 | class BookForm(ModelForm):
11 | class Meta:
12 | model = Book
13 | fields = ['name', 'pages']
14 |
15 | class ReviewForm(ModelForm):
16 | class Meta:
17 | model = Review
18 | fields = ['person', 'review']
--------------------------------------------------------------------------------
/apps/books_pc_multi_view2/migrations/0001_initial.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.13 on 2020-06-25 16:03
2 |
3 | from django.db import migrations, models
4 | import django.db.models.deletion
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | initial = True
10 |
11 | dependencies = [
12 | ]
13 |
14 | operations = [
15 | migrations.CreateModel(
16 | name='Book',
17 | fields=[
18 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
19 | ('name', models.CharField(max_length=200)),
20 | ('pages', models.IntegerField()),
21 | ],
22 | ),
23 | migrations.CreateModel(
24 | name='Person',
25 | fields=[
26 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
27 | ('name', models.CharField(max_length=200)),
28 | ('email', models.EmailField(max_length=254)),
29 | ],
30 | ),
31 | migrations.CreateModel(
32 | name='Review',
33 | fields=[
34 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
35 | ('review', models.TextField()),
36 | ('book', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='books_pc_multi_view2.Book')),
37 | ('person', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='books_pc_multi_view2.Person')),
38 | ],
39 | ),
40 | ]
41 |
--------------------------------------------------------------------------------
/apps/books_pc_multi_view2/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rayed/django-crud-parent-child/982f70f1ad762fca52500de09555371f1bcba8ac/apps/books_pc_multi_view2/migrations/__init__.py
--------------------------------------------------------------------------------
/apps/books_pc_multi_view2/models.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 |
3 |
4 | class Person(models.Model):
5 | name = models.CharField(max_length=200)
6 | email = models.EmailField()
7 |
8 | def __str__(self):
9 | return self.name
10 |
11 |
12 | class Book(models.Model):
13 | name = models.CharField(max_length=200)
14 | pages = models.IntegerField()
15 |
16 | def __str__(self):
17 | return self.name
18 |
19 |
20 | class Review(models.Model):
21 | book = models.ForeignKey(Book,on_delete=models.CASCADE)
22 | person = models.ForeignKey(Person,on_delete=models.CASCADE)
23 | review = models.TextField()
24 |
25 | def __str__(self):
26 | return "Review from: " + self.person.name
27 |
--------------------------------------------------------------------------------
/apps/books_pc_multi_view2/templates/books_pc_multi_view2/book_confirm_delete.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block content %}
4 | {% include "books_pc_multi_view2/nav.html" with book=book title="Delete" %}
5 |
6 |
10 | {% endblock %}
11 |
--------------------------------------------------------------------------------
/apps/books_pc_multi_view2/templates/books_pc_multi_view2/book_form.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 |
4 | {% block content %}
5 | {% include "books_pc_multi_view2/nav.html" with book=book title="Edit" %}
6 |
10 | {% endblock %}
11 |
--------------------------------------------------------------------------------
/apps/books_pc_multi_view2/templates/books_pc_multi_view2/book_view.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 |
4 | {% block content %}
5 | {% include "books_pc_multi_view2/nav.html" with book=book title="View" %}
6 |
7 | Pages: {{ book.pages }}
8 |
9 | Reviews
10 |
11 | {% for review in reviews %}
12 | -
13 | {{ review.person }}
14 | {{ review.review|linebreaks }}
15 |
16 | edit
17 | delete
18 |
19 | {% endfor %}
20 |
21 |
22 | New Review
23 | {% endblock %}
24 |
--------------------------------------------------------------------------------
/apps/books_pc_multi_view2/templates/books_pc_multi_view2/home.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block title %}Book List{% endblock %}
4 |
5 | {% block content %}
6 | {% include "books_pc_multi_view2/nav.html" %}
7 |
8 | Books Parent/Child with Multi View and Foreign Key
9 |
10 | People
11 |
12 | {% for person in persons %}
13 | - {{ person.name }} ({{ person.email }})
14 | edit
15 | delete
16 |
17 | {% endfor %}
18 |
19 |
20 | New
21 |
22 |
23 | Books
24 |
25 | {% for book in books %}
26 | - {{ book.name }} ({{ book.pages }} Pages)
27 | view
28 | edit
29 | delete
30 |
31 | {% endfor %}
32 |
33 |
34 | New
35 | {% endblock %}
36 |
--------------------------------------------------------------------------------
/apps/books_pc_multi_view2/templates/books_pc_multi_view2/nav.html:
--------------------------------------------------------------------------------
1 |
2 | Application Home
3 | {% if book %}
4 | > {{ book.name }}
5 | {% endif %}
6 | {% if title %}
7 | > {{ title }}
8 | {% endif %}
9 |
--------------------------------------------------------------------------------
/apps/books_pc_multi_view2/templates/books_pc_multi_view2/person_confirm_delete.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block content %}
4 | {% include "books_pc_multi_view2/nav.html" with person=person title="Delete" %}
5 |
6 |
10 |
11 | {% endblock %}
12 |
--------------------------------------------------------------------------------
/apps/books_pc_multi_view2/templates/books_pc_multi_view2/person_form.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block content %}
4 | {% include "books_pc_multi_view2/nav.html" with person=person title="Edit Person" %}
5 |
6 |
10 |
11 | {% endblock %}
12 |
--------------------------------------------------------------------------------
/apps/books_pc_multi_view2/templates/books_pc_multi_view2/review_confirm_delete.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 |
4 | {% block content %}
5 | {% include "books_pc_multi_view2/nav.html" with book=book title="Delete Review" %}
6 |
10 | {% endblock %}
11 |
--------------------------------------------------------------------------------
/apps/books_pc_multi_view2/templates/books_pc_multi_view2/review_form.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 |
4 | {% block content %}
5 | {% include "books_pc_multi_view2/nav.html" with book=book title="Edit Review" %}
6 |
10 | {% endblock %}
11 |
--------------------------------------------------------------------------------
/apps/books_pc_multi_view2/tests.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 |
3 | # Create your tests here.
4 |
--------------------------------------------------------------------------------
/apps/books_pc_multi_view2/urls.py:
--------------------------------------------------------------------------------
1 | from django.urls import path
2 |
3 | from . import views
4 |
5 | app_name = 'books_pc_multi_view2'
6 |
7 | urlpatterns = [
8 | path('', views.home, name='home'),
9 |
10 | path('person_new', views.person_create, name='person_new'),
11 | path('person_edit//', views.person_update, name='person_edit'),
12 | path('person_delete//', views.person_delete, name='person_delete'),
13 |
14 | path('book_view//', views.book_view, name='book_view'),
15 | path('book_new', views.book_create, name='book_new'),
16 | path('book_edit//', views.book_update, name='book_edit'),
17 | path('book_delete//', views.book_delete, name='book_delete'),
18 |
19 | path('review_new//', views.review_create, name='review_new'),
20 | path('review_edit//', views.review_update, name='review_edit'),
21 | path('review_delete//', views.review_delete, name='review_delete'),
22 | ]
23 |
--------------------------------------------------------------------------------
/apps/books_pc_multi_view2/views.py:
--------------------------------------------------------------------------------
1 | from django.shortcuts import render, redirect, get_object_or_404
2 |
3 | from .models import Person, Book, Review
4 | from .forms import PersonForm, BookForm, ReviewForm
5 |
6 |
7 | # ========== Home =========
8 |
9 | def home(request, template_name='books_pc_multi_view2/home.html'):
10 | books = Book.objects.all()
11 | persons = Person.objects.all()
12 | ctx = {
13 | 'books': books,
14 | 'persons': persons,
15 | }
16 | return render(request, template_name, ctx)
17 |
18 |
19 | # ========== Book CRUD =========
20 |
21 | def book_view(request, pk, template_name='books_pc_multi_view2/book_view.html'):
22 | book= get_object_or_404(Book, pk=pk)
23 | reviews = Review.objects.filter(book=book)
24 | ctx = {
25 | 'book': book,
26 | 'reviews': reviews,
27 | }
28 | return render(request, template_name, ctx)
29 |
30 | def book_create(request, template_name='books_pc_multi_view2/book_form.html'):
31 | form = BookForm(request.POST or None)
32 | if form.is_valid():
33 | form.save()
34 | return redirect('books_pc_multi_view2:home')
35 | ctx = {
36 | 'form': form,
37 | }
38 | return render(request, template_name, ctx)
39 |
40 | def book_update(request, pk, template_name='books_pc_multi_view2/book_form.html'):
41 | book= get_object_or_404(Book, pk=pk)
42 | form = BookForm(request.POST or None, instance=book)
43 | if form.is_valid():
44 | form.save()
45 | return redirect('books_pc_multi_view2:home')
46 | ctx = {
47 | 'form': form,
48 | 'book': book,
49 | }
50 | return render(request, template_name, ctx)
51 |
52 | def book_delete(request, pk, template_name='books_pc_multi_view2/book_confirm_delete.html'):
53 | book= get_object_or_404(Book, pk=pk)
54 | if request.method=='POST':
55 | book.delete()
56 | return redirect('books_pc_multi_view2:home')
57 | ctx = {
58 | 'object': book,
59 | 'book': book,
60 | }
61 | return render(request, template_name, ctx)
62 |
63 |
64 | # ========== Review CRUD =========
65 |
66 | def review_create(request, parent_pk, template_name='books_pc_multi_view2/review_form.html'):
67 | book = get_object_or_404(Book, pk=parent_pk)
68 | form = ReviewForm(request.POST or None)
69 | if form.is_valid():
70 | review = form.save(commit=False)
71 | review.book = book
72 | review.save()
73 | return redirect('books_pc_multi_view2:book_view', parent_pk)
74 | ctx = {
75 | 'form': form,
76 | 'book': book,
77 | }
78 | return render(request, template_name, ctx)
79 |
80 | def review_update(request, pk, template_name='books_pc_multi_view2/review_form.html'):
81 | review = get_object_or_404(Review, pk=pk)
82 | parent_pk = review.book.pk
83 | form = ReviewForm(request.POST or None, instance=review)
84 | if form.is_valid():
85 | form.save()
86 | return redirect('books_pc_multi_view2:book_view', parent_pk)
87 | ctx = {
88 | 'form': form,
89 | 'book': review.book,
90 | }
91 | return render(request, template_name, ctx)
92 |
93 | def review_delete(request, pk, template_name='books_pc_multi_view2/review_confirm_delete.html'):
94 | review = get_object_or_404(Review, pk=pk)
95 | parent_pk = review.book.pk
96 | if request.method=='POST':
97 | review.delete()
98 | return redirect('books_pc_multi_view2:book_view', parent_pk)
99 | ctx = {
100 | 'object': review,
101 | 'book': review.book,
102 | }
103 | return render(request, template_name, ctx)
104 |
105 |
106 | # ============ Person CRUD ===============
107 |
108 | def person_create(request, template_name='books_pc_multi_view2/person_form.html'):
109 | form = PersonForm(request.POST or None)
110 | if form.is_valid():
111 | form.save()
112 | return redirect('books_pc_multi_view2:home')
113 | ctx = {
114 | 'form': form,
115 | }
116 | return render(request, template_name, ctx)
117 |
118 | def person_update(request, pk, template_name='books_pc_multi_view2/person_form.html'):
119 | person = get_object_or_404(Person, pk=pk)
120 | form = PersonForm(request.POST or None, instance=person)
121 | if form.is_valid():
122 | form.save()
123 | return redirect('books_pc_multi_view2:home')
124 | ctx = {
125 | 'form': form,
126 | }
127 | return render(request, template_name, ctx)
128 |
129 | def person_delete(request, pk, template_name='books_pc_multi_view2/person_confirm_delete.html'):
130 | person= get_object_or_404(Person, pk=pk)
131 | if request.method=='POST':
132 | person.delete()
133 | return redirect('books_pc_multi_view2:home')
134 | ctx = {
135 | 'person': person,
136 | }
137 | return render(request, template_name, ctx)
138 |
--------------------------------------------------------------------------------
/apps/books_simple/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rayed/django-crud-parent-child/982f70f1ad762fca52500de09555371f1bcba8ac/apps/books_simple/__init__.py
--------------------------------------------------------------------------------
/apps/books_simple/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 | from books_simple.models import Book
3 |
4 | admin.site.register(Book)
--------------------------------------------------------------------------------
/apps/books_simple/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class BooksSimpleConfig(AppConfig):
5 | name = 'books_simple'
6 |
--------------------------------------------------------------------------------
/apps/books_simple/forms.py:
--------------------------------------------------------------------------------
1 | from django.forms import ModelForm
2 |
3 | from .models import Book
4 |
5 | class BookForm(ModelForm):
6 | class Meta:
7 | model = Book
8 | fields = ['name', 'pages']
9 |
10 |
--------------------------------------------------------------------------------
/apps/books_simple/migrations/0001_initial.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.13 on 2020-06-25 16:03
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | initial = True
9 |
10 | dependencies = [
11 | ]
12 |
13 | operations = [
14 | migrations.CreateModel(
15 | name='Book',
16 | fields=[
17 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
18 | ('name', models.CharField(max_length=200)),
19 | ('pages', models.IntegerField()),
20 | ],
21 | ),
22 | ]
23 |
--------------------------------------------------------------------------------
/apps/books_simple/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rayed/django-crud-parent-child/982f70f1ad762fca52500de09555371f1bcba8ac/apps/books_simple/migrations/__init__.py
--------------------------------------------------------------------------------
/apps/books_simple/models.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 |
3 | class Book(models.Model):
4 | name = models.CharField(max_length=200)
5 | pages = models.IntegerField()
6 |
7 | def __str__(self):
8 | return self.name
9 |
--------------------------------------------------------------------------------
/apps/books_simple/templates/books_simple/book_confirm_delete.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block content %}
4 | {% include "books_simple/nav.html" with book=book title="Delete" %}
5 |
6 |
10 |
11 | {% endblock %}
12 |
--------------------------------------------------------------------------------
/apps/books_simple/templates/books_simple/book_form.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block content %}
4 | {% include "books_simple/nav.html" with book=book title="Edit" %}
5 |
6 |
10 |
11 | {% endblock %}
12 |
--------------------------------------------------------------------------------
/apps/books_simple/templates/books_simple/home.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block content %}
4 | {% include "books_simple/nav.html" with book=book %}
5 |
6 |
7 | {% for book in books %}
8 | - {{ book.name }} ({{ book.pages }} Pages)
9 | edit
10 | delete
11 |
12 | {% endfor %}
13 |
14 |
15 | New
16 | {% endblock %}
17 |
--------------------------------------------------------------------------------
/apps/books_simple/templates/books_simple/nav.html:
--------------------------------------------------------------------------------
1 |
2 | Application Home
3 | {% if book %}
4 | > {{ book }}
5 | {% endif %}
6 | {% if title %}
7 | > {{ title }}
8 | {% endif %}
9 |
--------------------------------------------------------------------------------
/apps/books_simple/tests.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 |
3 | # Create your tests here.
4 |
--------------------------------------------------------------------------------
/apps/books_simple/urls.py:
--------------------------------------------------------------------------------
1 | from django.urls import path
2 |
3 | from . import views
4 |
5 | app_name = 'books_simple'
6 |
7 | urlpatterns = [
8 | path('', views.home, name='home'),
9 | path('new/', views.book_create, name='book_new'),
10 | path('edit//', views.book_update, name='book_edit'),
11 | path('delete//', views.book_delete, name='book_delete'),
12 | ]
13 |
--------------------------------------------------------------------------------
/apps/books_simple/views.py:
--------------------------------------------------------------------------------
1 | from django.shortcuts import render, redirect, get_object_or_404
2 |
3 | from .models import Book
4 | from .forms import BookForm
5 |
6 | def home(request, template_name='books_simple/home.html'):
7 | books = Book.objects.all()
8 | ctx = {
9 | 'books': books,
10 | }
11 | return render(request, template_name, ctx)
12 |
13 | def book_create(request, template_name='books_simple/book_form.html'):
14 | form = BookForm(request.POST or None)
15 | if form.is_valid():
16 | form.save()
17 | return redirect('books_simple:home')
18 | ctx = {
19 | 'form': form,
20 | }
21 | return render(request, template_name, ctx)
22 |
23 | def book_update(request, pk, template_name='books_simple/book_form.html'):
24 | book = get_object_or_404(Book, pk=pk)
25 | form = BookForm(request.POST or None, instance=book)
26 | if form.is_valid():
27 | form.save()
28 | return redirect('books_simple:home')
29 | ctx = {
30 | 'form': form,
31 | 'book': book,
32 | }
33 | return render(request, template_name, ctx)
34 |
35 | def book_delete(request, pk, template_name='books_simple/book_confirm_delete.html'):
36 | book = get_object_or_404(Book, pk=pk)
37 | if request.method=='POST':
38 | book.delete()
39 | return redirect('books_simple:home')
40 | ctx = {
41 | 'book': book,
42 | }
43 | return render(request, template_name, ctx)
44 |
--------------------------------------------------------------------------------
/apps/manage.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | """Django's command-line utility for administrative tasks."""
3 | import os
4 | import sys
5 |
6 |
7 | def main():
8 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'apps.settings')
9 | try:
10 | from django.core.management import execute_from_command_line
11 | except ImportError as exc:
12 | raise ImportError(
13 | "Couldn't import Django. Are you sure it's installed and "
14 | "available on your PYTHONPATH environment variable? Did you "
15 | "forget to activate a virtual environment?"
16 | ) from exc
17 | execute_from_command_line(sys.argv)
18 |
19 |
20 | if __name__ == '__main__':
21 | main()
22 |
--------------------------------------------------------------------------------
/apps/theme/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rayed/django-crud-parent-child/982f70f1ad762fca52500de09555371f1bcba8ac/apps/theme/__init__.py
--------------------------------------------------------------------------------
/apps/theme/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 |
3 | # Register your models here.
4 |
--------------------------------------------------------------------------------
/apps/theme/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class ThemeConfig(AppConfig):
5 | name = 'theme'
6 |
--------------------------------------------------------------------------------
/apps/theme/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rayed/django-crud-parent-child/982f70f1ad762fca52500de09555371f1bcba8ac/apps/theme/migrations/__init__.py
--------------------------------------------------------------------------------
/apps/theme/models.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 |
3 | # Create your models here.
4 |
--------------------------------------------------------------------------------
/apps/theme/static/css/style.css:
--------------------------------------------------------------------------------
1 | * {
2 | font-family:arial;
3 | }
4 | pre {
5 | font-family:'Courier New', Courier, monospace;
6 | }
7 | a:visited {
8 | color:navy;
9 | }
10 |
11 | #wrapper {
12 | width:960px;
13 | margin:auto;
14 | }
--------------------------------------------------------------------------------
/apps/theme/templates/base.html:
--------------------------------------------------------------------------------
1 | {% load staticfiles %}
2 |
3 |
4 |
5 | Django CRUD: {% block title %}Welcome{% endblock %}
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | {% block content %}{% endblock %}
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/apps/theme/templates/home.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block content %}
4 |
5 |
12 |
13 | You can also access Django built-in Admin interface, you would need to
14 | create a user using the following command:
15 |
16 | ./manage.py createsuperuser
17 | {% endblock %}
18 |
--------------------------------------------------------------------------------
/apps/theme/tests.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 |
3 | # Create your tests here.
4 |
--------------------------------------------------------------------------------
/apps/theme/views.py:
--------------------------------------------------------------------------------
1 | from django.shortcuts import render
2 |
3 | def home(request):
4 | return render(request, 'home.html')
5 |
6 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | Django>=3.2.7,<4.0
--------------------------------------------------------------------------------
/www/media/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
--------------------------------------------------------------------------------
/www/static/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
--------------------------------------------------------------------------------