Django admin Inline Model Admin required - django

Having a such model below, how can I require atleast one book to be added while creating/editting Author instance at admin panel?
#models.py
class Author(models.Model):
name = models.CharField(max_length=100)
class Book(models.Model):
author = models.ForeignKey(Author)
title = models.CharField(max_length=100)
#admin.py
class BookInline(admin.TabularInline):
model = Book
class AuthorAdmin(admin.ModelAdmin):
inlines = [
BookInline,
]

Matthew Flanagan has a formset class that will do just that: http://wadofstuff.blogspot.com/2009/08/requiring-at-least-one-inline-formset.html
Hope that helps you out.

Related

DRY fields in Django models

I know about using inheritance and abstract models in reusing common fields in different models.
I'd like to know if the following approach is possible instead of inheritance and mixins.
from django.db import models
common_modified_by = models.CharField()
class Author(models.Model):
name = models.CharField()
modified_by = common_modified_by
class Book(models.Model):
title = models.CharField()
modified_by = common_modified_by
Will the above code work? Why or why not?
The issue with reusing the same field in multiple models is that the model attribute of the field will be set to the last model where the field is defined
from django.db import models
common_modified_by = models.CharField(max_length=20)
class Author(models.Model):
name = models.CharField(max_length=20)
modified_by = common_modified_by
class Book(models.Model):
title = models.CharField(max_length=20)
modified_by = common_modified_by
The field now has Book as it's model even when you get the field from the Author model. This can be problematic
>>> Book._meta.get_field('modified_by').model
<class 'foo.models.Book'>
>>> Author._meta.get_field('modified_by').model
<class 'foo.models.Book'>
One issue could be using the field as the target of a foreign key django.db.models.fields.related seems to use this model attribute quite a lot
It's also used when generating subqueries

Django admin multiple querysets on one page

How to have multiple tables(queryset) on one page in django admin.
For example:
When i go to the company page, i can see the list of departments in the company, i can also see the list of employees in the company.
You can use InlineModelAdmin objects to implement this, although if you want to do nested inlines you should check out this post. Although as that post says:
...it would be a kind of convoluted design to implement.
You didn't provide any code here so the best I can do is guess your model relationships.
models.py
from django.db import models
class Department(models.Model):
name = models.CharField(max_length=250)
...
class Employee(models.Model):
name = models.CharField(max_length=250)
...
class Company(models.Model):
name = models.CharField(max_length=250)
departments = models.ForeignKey(Department)
employees = models.ForeignKey(Employee)
...
admin.py
from django.contrib import admin
class EmployeeInline(admin.StackedInline):
model = Employee
class DepartmentInline(admin.StackedInline):
model = Department
class CompanyAdmin(admin.ModelAdmin):
list_display = ('name')
inlines = [DepartmentInline, EmployeeInline]
admin.site.register(CompanyAdmin)

Show inline model field in list_display

I have two models:
class Person(models.Model):
person_name = models.CharField(max_length=255)
def __unicode__(self):
return self.person_name
and
class Book(models.Model):
link = models.ForeignKey(Person)
book_name = models.CharField(max_length=255)
book_year = models.CharField(max_length=255)
book_email = models.CharField(max_length=255)
def __unicode__(self):
return self.name
admin.py
class PersonAdmin(admin.ModelAdmin):
inlines = ('BookInline',)
list_display = ('person_name', ...)
class BookInline(admin.TabularInline):
model = Book
extra = 1
max_num = 1
In PersonAdmin list_display, how can i show the inline model Book fields (title, name, email).
so when i access Person list of entries in django admin, i see:
person name book name book year book email
The list_display for the PersonAdmin is meant to display each person once. It doesn't really make sense to include attributes from the book model, because then you would have to include the person multiple times if they have more than one book.
Wouldn't it be better to include the person's name on the book's list_display?
class BookAdmin(admin.ModelAdmin):
inlines = ('BookInline',)
list_display = ('person_name', 'book_name', 'book_email', 'book_year')
def person_name(self, obj):
return obj.link.person_name
admin.site.register(Book, BookAdmin)
According to the doc, you can use a callable to display your fields.
Edit (2021/03/21): the link to the 1.9 doc is not working anymore, but the source is still available. I add the link to the dev version too.
class BookInline(admin.StackedInline):
model = Book
extra = 1
max_num = 1
StackedInline will solve your problem

InlineModelAdmin not showing up on admin page

I have
from django.db import models
from django.contrib import admin
# Create your models here.
class Author(models.Model):
name = models.CharField(max_length=10)
class Book(models.Model):
author = models.ForeignKey(Author, null=True, blank=True)
title = models.CharField(max_length=10)
class BookInline(admin.TabularInline):
model = Book
class AuthorAdmin(admin.ModelAdmin):
inlines = [
BookInline,
]
registered on my admin page, however books are not showing up in the author's admin page. Am I misunderstanding how this will work? I want to be able to add and remove books from the author on the admin page.
This is what you should have in admins.py:
from django.contrib import admin
from models import Author, Book
class BookInline(admin.StackedInline):
model = Book
class AuthorAdmin(admin.ModelAdmin):
inlines = [ BookInline ]
admin.site.register(Author, AuthorAdmin)
admin.site.register(Book)
You probably forgot to include 'AuthorAdmin' in this line:
admin.site.register(Author, AuthorAdmin)

Django OneToOneField and Admin UI

I am having a confusion on how to model a relationship in Django so that it can be edited inline in the Django Admin.
Let me explain the scenario.
I have a Customer Model and An Address Model. In the customer model I have a OneToOneField relationship to Address once for billing and once for shipping address.
class Address(models.Model):
pass
class Employee(models.Model):
billing_address = models.OneToOneField(Address)
shipping_address = models.OneToOneField(Address)
# Many more such fields
Now with this model there is no easy way to make them inline in Admin. I have tried the following
class AddressInline(admin.TabularInline):
model = Address
class Customer(admin.ModelAdmin):
inlines = [AddressInline, ]
I keep getting an error,
<class 'employee.admin.AddressInline'>: (admin.E202) 'employee.Address' has no ForeignKey to 'employee.Customer'.
Now I know there are other bugs similar to this one. ie. Use OneToOneField inlined in Django Admin and Django admin - OneToOneField inline throws "has no ForeignKey" exception
But I think my question is slightly different to warrant this post. Please help!
#1
models.py
class BillingAddress(models.Model):
employee = models.OneToOneField(to=Employee, related_name='billing_address')
class Employee(models.Model):
# Many more such fields
admin.py
class AddressInline(admin.TabularInline):
model = BillingAddress
extra = 1
#admin.register(Employee)
class EmployeeAdmin(admin.ModelAdmin):
inlines = [AddressInline, ]
#2
models.py
class Address(models.Model):
name = models.CharField(max_length=250)
employee = models.ForeignKey(to=Employee, related_name='addresses')
class Employee(models.Model):
# Many more such fields
admin.py
class AddressInline(admin.TabularInline):
model = Address
#admin.register(Employee)
class EmployeeAdmin(admin.ModelAdmin):
inlines = [AddressInline, ]
Full Example:
models.py
class Company(models.Model):
pass
class CompanyScheduler(models.Model):
company = models.OneToOneField(
to=Company,
related_name='scheduling',
on_delete=models.CASCADE,
)
start = models.DateField()
finish = models.DateField()
admin.py
class CompanySchedulerInLine(admin.TabularInline):
model = CompanySchedulerInLine
extra = 1
#admin.register(CompanyModelAdmin)
class CompanyModelAdmin(admin.ModelAdmin):
inlines = [
SchedulerInLine,
]
UI