django admin inline has no foreign key relation - django

I have a model like:
class Category(models.Model):
name = models.CharField(max_length=100)
description = models.TextField()
thumbnail = models.ForeignKey(MediaFile)
def __unicode__(self):
return self.name
Here I have thumbnail foreign key to MediaFile.
I want to have Inline of Category model.
I have done this :
class MediaInline(admin.StackedInline):
model = MediaFile
extra = 0
max_num=0
class CategoryAdmin(admin.ModelAdmin):
list_display = ('name',)
inlines = [ MediaInline, ]
admin.site.register(Category, CategoryAdmin)
Its not happening.. Here I am assuming to have MediaFile Inline to Category . What is wrong in here ?

Your foreign key is the wrong way round. If you want multiple mediafiles in one category, the fk needs to live on the MediaFile model. That way the inline will work.

You cannot set inlines this way because Category instance will be saved before MediaFile. Yet, Django wouldn't be able to set Category.thumbnail while MediaFile is not saved.
You should rather have a CategoryInline in MediaFileAdmin for instance.

Related

Display information about linked models fields in the django admin

These are my models:
class Partner(models.Model):
name = models.CharField(max_length=200, verbose_name="Organisation name")
class ResearchActivity(models.Model):
title = models.CharField(max_length=200)
partner = models.ManyToManyField(ActivityPartner, blank=True)
I'd like, in the Django administration forms, to have a field in my Partner edit form representing the ResearchActivity linked to that Partner.
Can this be achieved by adding a field to my Partner model (say, naming it linked_partner) and then edit my admin.py like so:
#admin.register(ActivityPartner)
class ActivityPartnerAdmin(admin.ModelAdmin):
search_fields = ['academic',]
autocomplete_fields = ['partnership_type', 'relationship_type', 'academic_links']
def get_changeform_initial_data(self, request):
return {'live_contract': ResearchActivity.objects.all().filter(linked_partner__id=request.ResearchActivity.partner.id)}
?
I have just come across in the display() decorator, new from Django 3.2. With it, I can simply do:
#admin.register(ActivityPartner)
class ActivityPartnerAdmin(admin.ModelAdmin):
search_fields = ['academic',]
autocomplete_fields = ['partnership_type', 'relationship_type', 'academic_links',]
readonly_fields = ('get_ra',)
#admin.display(description='Live contract(s)')
def get_ra(self, obj):
return list(ResearchActivity.objects.filter(partner=obj.id))
to achieve what I want.
If I also wanted to edit those ManyToMany relations, I can use the inlines option:
class LiveContractsInline(admin.TabularInline):
model = ResearchActivity.partner.through
#admin.register(ActivityPartner)
class ActivityPartnerAdmin(admin.ModelAdmin):
inlines = [
LiveContractsInline,
]

How to display table with group same values in the column on Django Admin

I have a Comment table on Django Admin:
models.py
class Comment(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
item = models.ForeignKey(Listing, on_delete=models.CASCADE)
comment = models.TextField(max_length=250)
datetime = models.DateTimeField(auto_now=True)
def __str__(self):
return f"{self.item}"
admin.py
class CommentInline(admin.TabularInline):
model = Comment
class ItemAdmin(admin.ModelAdmin):
inlines = [
CommentInline,
]
#admin.register(Comment)
class CommentAdmin(admin.ModelAdmin):
list_display = ('item','user','comment','datetime',)
list_filter = ('item',)
And I want to edit this table with the same values item that will display with a single row, and then after clicked on it will display another table contain user comment and datetime .
Thanks so much for any advice to me !!!
If item is a foreign key to one of your other models, you should be able to use an InlineModelAdmin object to create a tabular inline view of the user/comment/datetime using the item's admin view.
See
https://docs.djangoproject.com/en/3.1/ref/contrib/admin/#inlinemodeladmin-objects for reference.
In your case you may end up with something like:
class CommentInline(admin.TabularInline):
model = Comment
fields = ('user', 'comment', 'datetime')
class ItemAdmin(admin.ModelAdmin):
inlines = [
CommentInline,
]
If item is a models.CharField though I don't think you can do it with the Django Admin as provided by Django.

Autofield column is not showing in admin database

i have created a model Post
class Post(models.Model):
id = models.AutoField(primary_key=True)
title = models.CharField(max_length=100)
image = models.ImageField(upload_to='blog_image', default='default.jpg')
smallContent = models.TextField()
content = models.TextField()
data_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.title
but id field is not showing in admin panel. i did makemigrations and migrate and both are done successfully.
AutoField is generated after the model is saved. It is not provided in Admin Panel as it should not be editable.
If want to make id editable (not recommended) override it as a CharField instead of AutoField with primary_key=True.
Else if just want to show it in the panel (while editing a saved model), add it to the read_only list of your model admin.
Read about AutoField here.
Since it is a readonly field I think you probably need to explicitly tell admin to show it.
I don't know if this will work but try in admin.py
from django.contrib import admin
from .models import Post
class PostAdmin(admin.ModelAdmin):
readonly_fields = ['display_id']
def display_id(self, obj):
return obj.id
admin.site.register(Post, PostAdmin)

Django admin show __str__ value in name

I have a many to many field like this:
class Retailer(models.Model):
name = models.CharField(max_length=100, db_index=True)
city_gps = models.ManyToManyField(City, blank=True, related_name='retailers', db_index=True)
def __str__(self):
retailer_city = ""
if self.city_gps:
retailer_city = self.city_gps.all().first().name
return slugify(self.name) + slugify(retailer_city)
I would like the admin to show a combination of the name and all related cities. However, when I set the admin to show this field like this:
class RetailerAdmin(admin.ModelAdmin):
search_fields = ['name']
list_display = ['name', 'city_gps', 'icon_tag', 'logo_tag', 'header_tag']
I get the error:
: (admin.E109) The value of
'list_display[1]' must not be a ManyToManyField.
So, how can I solve this? Is there a way to show the value of the __str__ method in the the admin?
As said in the docs for list_display in Django:
ManyToManyField fields aren’t supported, because that would entail executing a separate SQL statement for each row in the table. If you want to do this nonetheless, give your model a custom method, and add that method’s name to list_display. (See below for more on custom methods in list_display.)
So you can define this custom method either in your models.py or (I think the more explicit way), directly in your admin.py:
class RetailerAdmin(admin.ModelAdmin):
search_fields = ['name']
list_display = ['name', 'icon_tag', 'logo_tag', 'header_tag', 'retailer_city']
def retailer_city(self, obj):
city_gps = obj.city_gps
retailer_city = city_gps.all().first().name if city_gps else ''
return slugify(obj.name) + slugify(retailer_city)
Note that retailer_city is added in list_display.

How to set up Django TabularInline so I can edit intermediate table object

I'm using a TabularInline editor to allow editing of a model's relationship to another model. It's a many-to-many thru a map table. Is there a way to get django to put in an icon-link to the map table itself in the rows of the tabularInline?
For example, If Machine and Part are mapped together by Machine2Part and I use a tabularInline within the Machine to provide editing of its Parts, I will get pulldown menus that allow me to select Parts which is great, but I also want a link that takes me to an admin form for the Machine2Part object/row that sits behind this relationship because my Machine2Part admin form has field editing that I want to be able to access from this location.
class Part (models.Model):
name = models.CharField(max_length=45)
class Meta:
db_table = "part"
def __str__ (self):
return self.name
class Machine (models.Model):
name = models.CharField(max_length=45)
parts = models.ManyToManyField(Part, through='Machine2Part')
class Meta:
db_table = "machine"
def __str__ (self):
return self.name
class Machine2Part (models.Model):
machine = models.ForeignKey(Machine,db_column='machineId')
part = models.ForeignKey(Part,db_column='partId')
class Meta:
db_table = "machine2part"
class Machine2PartInline (admin.TabularInline):
# fields = ['name']
model = Machine2Part
class MachineAdmin (admin.ModelAdmin):
inlines = [Machine2PartInline]
admin.site.register(Machine, MachineAdmin)
admin.site.register(Part)
admin.site.register(Machine2Part)
The show_change_link = True will add a "Change" link next to each row in the TabularInline
class Machine2PartInline (admin.TabularInline):
# fields = ['name']
model = Machine2Part
show_change_link = True
If your model Machine2Part contains additional fields (besides the FKs) you can use this to show the fields inside the inline, no need for additional link.
class Machine2PartInline (admin.TabularInline):
model = Machine.parts.through
See django docs reference