I using a nested model in a Django project.
The following snippet code is models.py:
from django.db import models
from django.db.models.deletion import CASCADE
class Model_(models.Model):
name = models.CharField(max_length=50, default="This is a model")
frequently = models.FloatField(default=1.0)
def __str__(self):
return self.name
class SubModel(models.Model):
name = models.CharField(max_length=100)
address = models.CharField(max_length=8, default='0x')
model_ = models.ForeignKey(Model_, on_delete=CASCADE)
def __str__(self):
return self.name
class Metadata(models.Model):
key = models.CharField(max_length=100)
value = models.CharField(max_length=100)
sub_model = models.ForeignKey(SubModel, on_delete=CASCADE)
This is my admin.py script:
from django.contrib import admin
from nested_inline.admin import NestedTabularInline, NestedStackedInline,\
NestedModelAdmin
from <djano-application-name>.models import Model_, SubModel, Metadata
class MetadataAdmin(NestedTabularInline):
model = Metadata
extra = 1
class SubModelAdmin(NestedStackedInline):
model = SubModel
inlines = [MetadataAdmin]
extra = 1
class Model_Admin(NestedModelAdmin):
model = Model_
inlines = [SubModelAdmin]
list_display = ['name']
admin.site.register(Model_, Model_Admin)
Question:
What is the difference between NestedStackedInline and NestedTabularInline in admin.py script?
[NOTE]:
Versions: Python 2.7 and Django 1.11
If you are using django-nested-inline, It means you wanted to edit models on the same page as a parent model and add more than 1 level of children at once with the parent object in admin.
The Django admin is just a normal Django application and you can't have a second level of inlines(nested forms) in the default Django admin.
The difference between NestedStackedInline and NestedTabularInline is just Layout. Indeed, both work exactly the same behind the scenes, the only difference is the template used for rendering. Check the official docs. So, picking one for your project is only a matter of preference regarding the interface layout.
This is how NestedStackedInline will look, each field of the model is under other.
and this is NestedTabularInline, each field of the model is in one line, column wise
Related
I have a model with an attribute that is connected to another model as follow:
class Book(models.Model):
synced = models.OneToOneField('SyncedBook'
related_name='internal',
on_delete=models.CASCADE)
# some more attributes here...
#property
def book_address(self)
return self.synced.book_address
However, the book_address is a also a FK in the SyncedBook table as follow:
book_address = models.ForeignKey('Address', db_index=True, null=True, blank=True,
related_name='address_book', on_delete=models.PROTECT)
I don't know and understand how to be able to edit the book_address through the Django admin page in class BookingAdmin(admin.ModelAdmin), even though I have read over the documentation. At first I have the attribute as readonly, but now I want to be able to edit it and save the new address from the Address table. Is there a way to make it happen through the class BookingAdmin(admin.ModelAdmin) and how? Any example and solution would be appreciate
Model properties are typically used for presenting logically defined data for a particular model instance and not necessarily storing data on the model instance itself.
An example of when to use a model property is as follows:
# Defines a product instance
class Product(model.Models):
name = models.CharField(max_length=100)
description = models.TextField()
active = models.BooleanField(default=True)
cost = models.DecimalField(max_digits=5, decimal_places=2)
price = models.DecimalField(max_digits=5, decimal_places=2)
# calculate profits on product
#property
def profit(self)
p = self.price - self.cost
return p
In your case, you are trying to actually be able to modify data against a related model instance within the django admin. To me this sounds like more specifically an Inline (click here for documentation)
So in your case, you would need to create something like the following to your admin.py file:
class SyncedBookInline(admin.TabularInline):
model = BookInline
#admin.Register(Book)
class BookAdmin(admin.ModelAdmin):
# all your model admin settings
inlines = [SyncedBookInline]
Additional Info:
The Inline solution should still work for you. Please see the working code listed below:
models.py:
from django.db import models
class Hero(models.Model):
name = models.CharField(max_length=50)
class HeroAcquaintance(models.Model):
name = models.CharField(max_length=50)
hero = models.OneToOneField(Hero, on_delete=models.CASCADE)
admin.py:
from django.contrib import admin
from .models import *
class HeroAcquaintanceInline(admin.TabularInline):
model = HeroAcquaintance
#admin.register(Hero)
class HeroAdmin(admin.ModelAdmin):
list_display = (
'name',
)
inlines = [HeroAcquaintanceInline]
#admin.register(HeroAcquaintance)
class HeroAcquaintanceAdmin(admin.ModelAdmin):
list_display = (
'name',
)
Screenshot:
I created an app with django and python3 containing several tutorials, which in turn contain multiple content entrys that are saved in another table. Each tutorial is represented by an entry in the exercises tutorial model. I want to be able to sort the tutorials and the contents in the django admin panel. It works fine for the inline tutorial contents with SortableInlineAdminMixin class. It also works fine if I create new tutorials from scratch without having any objects saved before (it works local on my pc if I clone this project and set it up from scratch)
My problem now is, that I have the app setup like you see in the code and pictures below on a ubuntu server with apache, but I can't sort the tutorials (the inline contents still work fine). If i drag and drop them to a new position and reload, they don't save at their new position and fall back to their old position.
Tutorial and TutorialContent model:
from django.db import models
from ckeditor_uploader.fields import RichTextUploadingField
# Page for tutorials
class Tutorial(models.Model):
title = models.CharField(max_length=60)
order = models.PositiveIntegerField(default=0, null=False, unique=True)
# Timestamp
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
ordering = ['order']
def __str__(self):
return self.title
# Content for tutorials
class TutorialContent(models.Model):
lesson_page = models.ForeignKey(Tutorial, related_name='tutorial_content', on_delete=models.CASCADE)
content = RichTextUploadingField()
order = models.PositiveIntegerField(default=0, null=False)
# Timestamp
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
ordering = ['order']
def __str__(self):
description = 'Order - ' + str(self.order)
return description
Tutorial and TutorialContent admin:
from django.contrib import admin
from .models import Tutorial, TutorialContent
from adminsortable2.admin import SortableInlineAdminMixin, SortableAdminMixin
class TutorialContentInline(SortableInlineAdminMixin, admin.TabularInline):
model = TutorialContent
class TutorialAdmin(SortableAdminMixin, admin.ModelAdmin):
model = Tutorial
inlines = [TutorialContentInline]
list_display = ['title']
admin.site.register(Tutorial, TutorialAdmin)
Django admin tutorial model panel:
SQLite3 view of the corresponding table:
Maybe a little to late, but:
If there is already some model instance persisted in your db when you add the adminsortable2 field in your model, the ordering will not works, you need to build the order a first time with:
python manage.py reorder your_app.YourModel
Source: https://django-admin-sortable2.readthedocs.io/en/latest/usage.html#initial-data
Hoping this can help.
Project Name : fusion
App Name : admin_lte
Python 3.7
Django 2
MySql
Question is "I want to register sub model in django admin-panel",when i write code for model registration in admin.py file that time occurred below error.
django.core.exceptions.ImproperlyConfigured: The model Device is abstract, so it cannot be registered with admin.
NOTE : I used multiple separated model file.
device.py (Model File)
from django.db import models
class Device(models.Model):
device_type = models.CharField(max_length=100,blank=False)
price = models.IntegerField()
status = models.CharField(max_length=10, default="SOLD")
issues = models.CharField(max_length=100, default="No Issues")
class Meta:
abstract = True
def __str__(self):
return 'Device_type:{0} Price:{1}'.format(self.device_type,self.price)
#Inheritance Concept
class Laptop(Device):
pass
class Meta:
db_table = "laptop"
class Desktop(Device):
pass
class Meta:
db_table = "Desktop"
class Mobile(Device):
pass
class Meta:
db_table = "Mobile"
__init__.py File
from django_adminlte.models.employee import Employee
from django_adminlte.models.device import Device
admin.py
from django.contrib import admin
from.models import Employee
from.models import Device
admin.site.register (Employee)
admin.site.register (Device)
I want to show sub model (Desktop,Laptop,Mobile) in admin panel so admin can add some data from admin panel.
Project Structure Image :
I can see in your code Device is a abstract model. So, we should not register it because abstract models do not have associated tables in databases.
from django.contrib import admin
from .models import Employee, Laptop, Mobile, Desktop
admin.site.register(Employee)
admin.site.register(Laptop)
admin.site.register(Mobile)
admin.site.register(Desktop)
I also got a problem when trying to generate an admin CRUD for a class inheriting from an abstract class. But the cause was different so I'll leave my case here in case it helps someone else.
In my case, the problem was that I forgot to make the abstract class inherit from django's models.Model.
Example Code:
time.py
from django.db import models
from applications.utils import UniqueNameMixin
class Month(UniqueNameMixin):
starting_date = models.DateField()
ending_date = models.DateField()
class TimeSensible(models.Model): # Here '(models.Model)' was missing.
class Meta:
abstract = True
month = models.ForeignKey(Month, models.PROTECT)
transaction.py
from django.db import models
from applications.core.models.cash_flow import Concept
from applications.core.models.financial_position import Account
from applications.core.models.time import TimeSensible
class Transaction(models.Model, TimeSensible):
concept = models.ForeignKey(Concept, models.PROTECT, blank=True, null=True)
amount = models.DecimalField(max_digits=10, decimal_places=2)
account = models.ForeignKey(Account, models.PROTECT)
detail = models.CharField(max_length=100, blank=True, null=True)
def __str__(self):
return '{} - {} - {} - {}'.format(self.month, self.concept, self.amount, self.account)
The error I got:
raise ImproperlyConfigured(
django.core.exceptions.ImproperlyConfigured: The model Transaction is abstract, so it cannot be registered with admin.
I have a Django related question about foreign keys in the admin panel. I'm facing the following situation:
class Driver(models.Model):
name = models.CharField(max_length=200)
executable = models.CharField(max_length=200)
class Device(models.Model):
name = models.CharField(max_length=200)
bound_driver = models.ForeignKey(Driver)
class DriverAssignment(models.Model):
device = models.ForeignKey(Device)
driver = models.ForeignKey(Driver)
Every device needs to have a bound driver (which it uses). DriverAssignment should be the table which shows which driver can be used by which device. So one device can have multiple possibilities of drivers which can be bound. Now i would like to have a dropdown on my admin panel showing all possible drivers for a specific device to select the 'bound_driver'.
How can i do this in Django? This is probably an easy thing for an experienced Django guy. I hope someone can give me a hint since i'm kind of new to Django. Thanks a lot!
For Django >1.8
Use the InlineModelAdmin (docs for 2.2) as explained there:
models.py
from django.db import models
class Author(models.Model):
name = models.CharField(max_length=100)
class Book(models.Model):
author = models.ForeignKey(Author, on_delete=models.CASCADE)
title = models.CharField(max_length=100)
admin.py
from django.contrib import admin
class BookInline(admin.TabularInline):
model = Book
class AuthorAdmin(admin.ModelAdmin):
inlines = [
BookInline,
]
Change your model Structure to This:
class Driver(models.Model):
name = models.CharField(max_length=200)
executable = models.CharField(max_length=200)
class Device(models.Model):
name = models.CharField(max_length=200)
bound_driver = models.ForeignKey(Driver, related_name="bound_to")
available_drivers = models.ManyToManyfield(Driver)
ManyToManyField would do the same work as DriverAssignment Table.
You can add Available drivers in Available drivers field.
But then You would also Want that bound_driver is one of the Available Drivers. This validation you will have to do in forms. For that you have to over-ride Admin forms. See links
Links of Reference:
ManytoMany field: https://docs.djangoproject.com/en/1.6/ref/models/fields/#django.db.models.ManyToManyField
Model Admin (to over-ride admin functionality):
https://docs.djangoproject.com/en/1.6/ref/contrib/admin/#modeladmin-objects
You will have to spend some time reading and implementing if you want ot learn more. :)
OR
If you want to go with the same structure, than you will have to over-ride the form in ModelAdmin see here and Provide you custom form, which will be something like this:
class CustomForm(ModelForm)
bound_driver = forms.ModelChoiceField(queryset = <your custom queryset that returns only available drivers>, ...)
class Meta:
model = Device
https://docs.djangoproject.com/en/1.6/ref/contrib/admin/#django.contrib.admin.ModelAdmin.form
There is a snippet for inverse inlines. If you still need it you may try this:
https://gist.github.com/mzbyszewska/8b6afc312b024832aa85
It has been used by me for OneToOneField in django 1.5 and 1.6. Unfortunately I did not test it for ForeignKeyField, but the one of the previous users claims that it works for ForeignKeyField either.
The best description of the snippet is contained in it. The Person class is your DriverAssignment class and Device correspond to the Address class in the example below:
Example:
from django.db import models
class Address(models.Model):
street = models.CharField(max_length = 255)
zipcode = models.CharField(max_length = 10)
city = models.CharField(max_length = 255)
class Person(models.Model):
name = models.CharField(max_length = 255)
business_addr = models.ForeignKey(Address,
related_name = 'business_addr')
home_addr = models.OneToOneField(Address, related_name = 'home_addr')
other_addr = models.OneToOneField(Address, related_name = 'other_addr')
You use reverseadmin in the following way:
from django.contrib import admin
from django.db import models
from models import Person
from reverseadmin import ReverseModelAdmin
class AddressForm(models.Form):
pass
class PersonAdmin(ReverseModelAdmin):
inline_type = 'tabular'
inline_reverse = ('business_addr', ('home_addr', AddressForm), ('other_addr' (
'form': OtherForm
'exclude': ()
)))
admin.site.register(Person, PersonAdmin)
inline_type can be either "tabular" or "stacked" for tabular and
stacked inlines respectively.
I'm trying to add an extra input to a admin.ModelAdmin for a model I have so I can record some optional text when another input has changed.
I can't get the custom ModelForm recognised as name 'EquipmentAdmin' is not defined. I've tried several different ways of importing but think I must have missed something obvious. It feels like there's a circular reference between the EquipmentAdmin and EquipmentAdminForm as they both include a reference to each other in the code.
I have created my Django application Flightdeck and have these all in the same folder;
models.py
from django.db import models
class Location(models.Model):
name = models.CharField(max_length=45)
class Equipment(models.Model):
unit_id = models.CharField(max_length=45)
located = models.ForeignKey(Location)
located_from = models.DateField()
class EquipmentLocationHistory(models.Model):
unit = models.ForeignKey(Equipment)
located = models.ForeignKey(Location)
start = models.DateField()
end = models.DateField()
change_reason = models.CharField(max_length=45)
admin.py
from django.contrib import admin
from flightdeck.models import *
from flightdeck.forms import EquipmentAdminForm
class EquipmentAdmin(admin.ModelAdmin):
form = EquipmentAdminForm
def save_model(self, request, obj, form, change):
if 'located' in form.changed_data:
try:
old = Equipment.objects.get(unit_id=obj.unit_id)
except Equipment.DoesNotExist:
old = None
if old:
if 'located' in form.changed_data:
located_history = EquipmentLocationHistory(unit=obj, located=old.located, start=old.located_from, end=obj.located_from)
located_history.save()
obj.save()
forms.py
from django import forms
from django.contrib import admin
class EquipmentAdminForm(forms.ModelForm):
reason = forms.CharField()
class Meta:
model = EquipmentAdmin
I would like to include the reason value when I add the EquipmentLocationHistory but can't test what I have as the EquipmentAdminForm isn't loaded.
EquipmentAdmin is not a model. Your ModelForm needs to reference Equipment
from django import forms
from django.contrib import admin
from flightdeck.models import Equipment
class EquipmentAdminForm(forms.ModelForm):
reason = forms.CharField()
class Meta:
model = Equipment
PS: when you have circular references, there are many ways around the problem. The best way with model imports and django is to use django.db.models.get_model('app', 'model')