I am trying to open django admin for the following models..
class FirstModel(models.Model):
name = models.CharField(max_length=100)
class SecondModel(models.Model):
name = models.CharField(max_length=100)
firstModel = models.ForeignKey(FirstModel, related_name='secondList')
class ThirdModel(models.Model):
name = models.CharField(max_length=100)
secondModel = models.ForeignKey(SecondModel, related_name='thirdList')
I am trying to create an admin.py for the following models as follows..
class ThirdModelInline(admin.TabularInline):
model = ThirdModel
extra = 1
class SecondModelInline(admin.StackedInline):
model = SecondModel
inlines = [ThirdModelInline]
class FirstModelAdmin(admin.ModelAdmin):
inlines = [SecondModelInline]
admin.site.register(FirstModel, FirstModelAdmin)
I want to be able to edit the SecondModel and ThirdModel as a recursive relation inside FirstModel. But this is not working. I tried to follow this link : [Model with recursive self relation in Django's admin
[1]: Model with recursive self relation in Django's admin. Any help would be appreciated. Thanks!!
Found a very good library after some websearch. Might help someone else..
https://github.com/s-block/django-nested-inline
django-nested-inline isn't (yet?) supported on latest django releases.
But you could consider using django-nested-admin that is almost the same.
Related
Here are my simplified models :
from django.contrib.contenttypes.fields import (
GenericForeignKey, GenericRelation)
from django.db import models
from django.utils.translation import ugettext_lazy as _
class Thing(models.Model):
'''
Our 'Thing' class
with a link (generic relationship) to an abstract config
'''
name = models.CharField(
max_length=128, blank=True,
verbose_name=_(u'Name of my thing'))
# Link to our configs
config_content_type = models.ForeignKey(
ContentType,
null=True,
blank=True)
config_object_id = models.PositiveIntegerField(
null=True,
blank=True)
config_object = GenericForeignKey(
'config_content_type',
'config_object_id')
class Config(models.Model):
'''
Base class for custom Configs
'''
class Meta:
abstract = True
name = models.CharField(
max_length=128, blank=True,
verbose_name=_(u'Config Name'))
thing = GenericRelation(
Thing,
related_query_name='config')
class FirstConfig(Config):
pass
class SecondConfig(Config):
pass
And Here's the admin:
from django.contrib import admin
from .models import FirstConfig, SecondConfig, Thing
class FirstConfigInline(admin.StackedInline):
model = FirstConfig
class SecondConfigInline(admin.StackedInline):
model = SecondConfig
class ThingAdmin(admin.ModelAdmin):
model = Thing
def get_inline_instances(self, request, obj=None):
'''
Returns our Thing Config inline
'''
if obj is not None:
m_name = obj.config_object._meta.model_name
if m_name == "firstconfig":
return [FirstConfigInline(self.model, self.admin_site), ]
elif m_name == "secondconfig":
return [SecondConfigInline(self.model, self.admin_site), ]
return []
admin.site.register(Thing, ThingAdmin)
So far, I've a Thing object with a FirstConfig object linked together.
The code is simplified: in an unrelevant part I manage to create my abstract Config at a Thing creation and set the right content_type / object_id.
Now I'd like to see this FirstConfig instance as an inline (FirstConfigInline) in my ThingAdmin.
I tried with the django.contrib.contenttypes.admin.GenericStackedInline, though it does not work with my current models setup.
I tried to play around with the fk_name parameter of my FirstConfigInline.
Also, as you can see, I tried to play around with the 'thing' GenericRelation attribute on my Config Model, without success..
Any idea on how to proceed to correctly setup the admin?
According to the Django Docs you have to define the ct_fk_field and the ct_field if they were changed from the default values. So it may be enough to set ct_field to config_content_type.
Hope it works!
edit: Those values have to be declared in the Inline:
class SecondConfigInline(admin.StackedInline):
model = SecondConfig
ct_fk_field = "config_object_id"
ct_field = "config_content_type"
edit2:
I just realized an error in my assumption. Usually you should declare the Foreignkey on the Inline-model. Depending on the rest of your code you could just remove the generic Foreignkey on Thing+the genericRelation on Config and declare a normal Foreignkey on the Config-Basemodel.
This question is old, but I'll give it a try anyway.
I think the solution depends on what kind of relation you intend to create between Thing and your Config subclasses.
many-to-one/one-to-many
The way it is currently set up, it looks like a many-to-one relation: each Thing points to a single Config subclass, and many Things can point to the same Config subclass. Due to the generic relation, each Thing can point to a different model (not necessarily a Config subclass, unless you do some extra work).
In this case I guess it would make more sense to put the inline on the admin for the Config. That is, create a GenericStackedInline for Thing (which has the GenericForeignkey), and add the inline to a ConfigAdmin, which you can then use for all Config subclasses. Also see the example below. The generic inline will then automatically set the correct content_type and object_id.
many-to-many
On the other hand, if you are looking for a many-to-many relation between Thing and each Config subclass, then I would move the GenericForeignkey into a separate many-to-many table (lets call it ThingConfigRelation).
A bit of code says more than a thousand words, so let's split up your Thing class as follows:
class Thing(models.Model):
name = models.CharField(max_length=128)
class ThingConfigRelation(models.Model):
thing = models.ForeignKey(to=Thing, on_delete=models.CASCADE)
content_type = models.ForeignKey(ContentType, null=True, blank=True,
on_delete=models.CASCADE)
object_id = models.PositiveIntegerField(null=True, blank=True)
config_object = GenericForeignKey(ct_field='content_type',
fk_field='object_id')
Now it does make sense to add an inline to the ThingAdmin. The following is a bare-bones example of an admin that works for both sides of the relation:
from django.contrib import admin
from django.contrib.contenttypes.admin import GenericStackedInline
from .models import Thing, FirstConfig, SecondConfig, ThingConfigRelation
class ConventionalTCRInline(admin.StackedInline):
model = ThingConfigRelation
extra = 0
class GenericTCRInline(GenericStackedInline):
model = ThingConfigRelation
extra = 0
class ThingAdmin(admin.ModelAdmin):
inlines = [ConventionalTCRInline]
class ConfigAdmin(admin.ModelAdmin):
inlines = [GenericTCRInline]
admin.site.register(Thing, ThingAdmin)
admin.site.register(FirstConfig, ConfigAdmin)
admin.site.register(SecondConfig, ConfigAdmin)
Note that we use the conventional inline for the ForeignKey-side of the relation (i.e. in ThingAdmin), and we use the generic inline for the GenericForeignKey-side (in ConfigAdmin).
A tricky bit would be filtering the content_type and object_id fields on the ThingAdmin.
... something completely different:
Another option might be to get rid of the GenericForeignKey altogether and use some kind of single-table inheritance implementation with plain old ForeignKeys instead, a bit like this.
I am really very much irritated by the extra "s" added after my class name in django admin eg class 'About' in my model.py becomes 'Abouts' in admin section. And i want it not to add extra 's'. Here is my model.py file-
class About(models.Model):
about_desc = models.TextField(max_length=5000)
def __unicode__(self): # __str__ on Python 3
return str(self.about_desc)
Please anybody suggest me how django can solve my problem.
You can add another class called Meta in your model to specify plural display name. For example, if the model's name is Category, the admin displays Categorys, but by adding the Meta class, we can change it to Categories.
I have changed your code to fix the issue:
class About(models.Model):
about_desc = models.TextField(max_length=5000)
def __unicode__(self): # __str__ on Python 3
return str(self.about_desc)
class Meta:
verbose_name_plural = "about"
For more Meta options, refer to https://docs.djangoproject.com/en/1.8/ref/models/options/
Take a look at the Model Meta in the django documentation.
Within a Model you can add class Meta this allows additional options for your model which handles things like singular and plural naming.
This can be used in the following way (in english we do not have sheeps) so verbose_name_plural can be used to override djangos attempt at pluralising words:
class Sheep(model.Model):
class Meta:
verbose_name_plural = 'Sheep'
inside model.py or inside your customized model file add class meta within a Model Class.
If not mentioned then a extra 's' will be added at the end of Model Class Name which will be visible in Django Admin Page.
class TestRoles(model.Model):
class Meta: verbose_name_plural = 'TestRoles'
Is there a way to use multiple Django extensions in the admin.site.register() inside admin.py? I'm using "simple-history" and "import-export" extensions, but I can only have one of them in the admin.site.register().
Example: I have a model named, "Cars", that is using the "simple-history" extension so I need admin.site.register(Cars, SimpleHistoryAdmin), as their documentation says it should. I want to use the import/export extension as well to the same "Cars" model, but the admin.site.register() doesn't take multiple arguments for me to add it.
models.py
class Cars(models.Model):
Year = models.CharField(max_length=30)
Make = models.CharField(max_length=30)
Model = models.CharField(max_length=30)
history = HistoricalRecords()
class Meta:
verbose_name_plural = "Car Table"
def __str__(self):
return self.Make
admin.py
class CarResource(resources.ModelResource):
class Meta:
model = Cars
fields = ('id','Year', 'Make', 'Model',)
class CarAdmin(ImportExportModelAdmin):
resource_class = CarResource
pass
#I want to use the import/export extension (code above), along with simple-history
admin.site.register(Cars, CarAdmin)
admin.site.register(Cars, SimpleHistoryAdmin)
I've tried using a proxy and inlines, but the proxy makes a new model which I don't want and when using inlines I get an error saying that it requires a foreign key, but I'm not trying to get the model objects from a different model. Naming them the same model doesn't work because the model is already registered. Any help is much appreciated!
In python, class can have more than one parent. Just inherit from 2 parents at once. But both ImportExportModelAdmin and SimpleHistoryAdmin are inheriting from ModelAdmin, that's not good. There is also ImportExportMixin, we can use it instead of ImportExportModelAdmin, so there will be only one reference to ModelAdmin.
class CarResource(resources.ModelResource):
class Meta:
model = Cars
fields = ('id','Year', 'Make', 'Model',)
class CarAdmin(ImportExportMixin, SimpleHistoryAdmin):
resource_class = CarResource
pass
#I want to use the import/export extension (code above), along with simple-history
admin.site.register(Cars, CarAdmin)
I'm having a strange riddle to solve:
I extended my django-1.4 user-objects with a UserProfile, as described at https://docs.djangoproject.com/en/dev/topics/auth/ and wanted to implement project-specific roles. So my models look like the following:
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True)
projects = models.ManyToManyField(Project, through='UserProjectRole')
[...]
class UserProjectRole(models.Model):
userProfile = models.ForeignKey(UserProfile)
project = models.ForeignKey(Project)
group = models.ForeignKey(Group)
[...]
I needed to pass a css-class, so I created a model-form for UserProjectRole and implemented the userProfile-Field with a widget:
class ProjectRoleForm(forms.ModelForm):
userProfile = forms.ModelMultipleChoiceField(label='Users',
queryset=UserProfile.objects.all(),
widget=forms.SelectMultiple(attrs={'class': 'select-multiple'}))
class Meta:
model = UserProjectRole
The form is presented correctly, however, it's crashing during save-process with the following error
Cannot assign "[<UserProfile: MyUser>]": "UserProjectRole.userProfile" must be a "UserProfile" instance.
Does anyone have an idea?
My guess is it's because you are using a forms.SelectMultiple widget. Which gives you a list of UserProfile instances ( [<UserProfile: MyUser>] ) and not a single UserProfile instance which is of course required to set on a ForeignKey field (UserProjectRole.userProfile). Thus I suggest to try using a forms.Select widget instead.
I've got a weird problem in django admin list_display. Whenever I add a foreign key to a list_display the whole change list view goes blank showing only the total no of entries.
models.py:
class Organization(models.Model):
org_id = models.AutoField(primary_key=True)
org_name = models.CharField(max_length=288)
def __unicode__(self):
return self.org_name
class Meta:
db_table = u'organization'
class Server(models.Model):
server_id = models.AutoField(primary_key=True)
server_name = models.CharField(max_length=135,verbose_name="Server Name")
org = models.ForeignKey(Organization,verbose_name="Organization")
def __unicode__(self):
return self.server_name
class Meta:
db_table = u'server'
admin.py:
class ServerAdmin(admin.ModelAdmin):
list_display = ('server_name','org')
admin.site.register(Server,ServerAdmin)
Now I'd expect this code to show me the organization name in the ChangeList View, But instead I get this:
If I remove the org in the list_display of ServerAdmin class, I get this:
I didn't modify the template or override any ModelAdmin methods. I'm using Mysql(5.1.58) as my database that comes with ubuntu 11.10 repository.
I'll be really glad if I could a get a sloution for this problem guys. Thanks in advance.
I second Stefano on the fact that null=True, blank=True is to be added. But, I think you only need to add it to the org_name field of the Organization model. That should make your way through. It has to be done because you have run inspectdb to create models from your legacy DB. And probably the organization table in the DB has an empty string stored. So, adding the above would allow the Admin to have a blank field/column displayed.
Moreover, you can also try using callbacks in situations where you don't want to make changes to your model definition like the above.
Try adding null=True, blank=True to all your model fields.
Usually django admin will silenty fail (thus show no records in the list) if the row does not validate the model constraints.
See: https://stackoverflow.com/a/163968/1104941
Does the following work for you?
admin.py:
class ServerAdmin(admin.ModelAdmin):
list_display = ('server_name','org__org_name')
admin.site.register(Server,ServerAdmin)
I had a similar problem and solved it like this (using your example):
class ServerAdmin(admin.ModelAdmin):
list_display = ('server_name', 'get_org')
def get_org(self, obj):
return obj.org.org_name
get_org.short_description = 'Org'
admin.site.register(Server,ServerAdmin)