Django Admin Select Objects based on ManyToMany Relationship - django

I'm working on building a django app that extends the Mezzanine project. Mezzanine has a Gallery app (photos). I'd like to create "portfolio" page that acts as a landing page which has a single image and link to each gallery page.
Each gallery (Gallery) can have multiple images (GalleryImage). I'd like to via the admin select a gallery, then select an image to be displayed. However, I can't seem to figure out what to do.
Here's my model:
class GalleriesThumb(models.Model):
relatedlandingpage = models.ForeignKey(LandingPage)
relatedgallery = models.ForeignKey(Galleries)
thumb = models.ManyToManyField(GalleryImage)
def __unicode__(self):
return self.name
class Galleries(models.Model):
landingpage = models.ForeignKey(LandingPage)
tagline = models.CharField(max_length=100)
galleries = models.ManyToManyField(Gallery)
def __unicode__(self):
return self.name
class LandingPage(models.Model):
gallerytitle = models.CharField(max_length=200)
def __unicode__(self):
return self.name
My admin is something like:
class GalleryInline(admin.InlineModelAdmin)
model = Galleries
model = GalleriesThumb
list_display = galleries
list_display = thumb
class LangingPageAdmin(admin.ModelAdmin):
fieldsets = (
(None, {
'fields': ('gallerytitle')
})
inlines = [GalleryInline,]
I realized that this won't do what i want, but how do I get the list_display on the the images that are related to Galleries. I'm pretty sure it needs to be a method, or am I taking a completing wrong approach if the selections that are made will be defining the content on the page. (I realize that I'm also missing my fields to store the selection in.)
I'm sorry if this a dumb question, but this my first real world attempt an app.

I think this link will resolve your problem
Django 1.2.1 Inline Admin for Many To Many Fields
class GalleryInline(admin.InlineModelAdmin)
model = Galleries.galleries.through

Related

Django Admin list_display: Link to filtered model

I want to make a music library app and in the admin/artist page I would like to link to a list with all the albums by the artist.
Models look like this:
class Artist(models.Model):
artistName = models.CharField(max_length=100, blank = False)
genre = models.CharField(max_length=100, blank = False)
def __str__(self):
return self.artistName
class Album(models.Model):
artist = models.ForeignKey(Artist, on_delete=models.CASCADE)
albumName = models.CharField(max_length=500, blank = False)
year = models.IntegerField(blank = False)
def __str__(self):
return self.albumName
Now for the admin part, I imagine that I make an ArtistAdmin model and then somehow use list_display to link to a filtered version of the Album model. Can anyone tell me how to do this or suggest a better way of doing it?
I'm having exactly the same need; here's the simplest way I came up so far.
Admin lists have list_filter, with which you can, for example, do that (assuming you register the admin classes and so on):
class AlbumAdmin(admin.ModelAdmin):
list_display = ('artist', 'albumName', 'year',)
list_filter = ('artist',)
This will add a right column in your admin site with the list of artists, and if you click on one, the Albums list will be filtered to show only those which are made by this artist.
Having that, and here's the trick, turns out that even if you don't declare "list_filter", Django will still filter things according to the URL parameters.
So, I activated the filters, I clicked in one of my "artists", so the list got filtered and I could see how it formats the URL, which is something like
[…]/admin/app_name/model_name/?foreignKeyName__id__exact=XX
In your case I imagine it will look similar to:
[…]/admin/music_library/album/?artist__id__exact=XX
Try to follow these steps, then remove the line "list_filter", and you will see that the URL still works.
So now we know that the only thing we need is to pass the param artist__id__exact=XX, so we have to append a column with a button for that.
class ArtistAdmin(admin.ModelAdmin):
list_display = ('artistName', 'genre', 'artists_list_field')
def artists_list_field(self, obj):
base_url = reverse('admin:music_library_album_changelist')
return mark_safe(u'Albums' % (
base_url, obj.id))
With this you have it working.
I hope it's useful!
You can use list_display and list_filter in admin.py like this:
class PersonAdmin(admin.ModelAdmin):
list_display = ('first_name', 'last_name',)
list_filter = ('company__name', 'first_name',) # company is a model which has relation to the Person model
Then in your admin.py you should add PersonAdmin to your model :
admin.site.register(Person, PersonAdmin)
Reference

Django Admin Extended View

I have built out a Django voting application. The models are pretty simple.
I have a category , an entry , and participant model
class Category(models.Model):
name = models.CharField(max_length=30)
slug = models.SlugField()
class Participant(models.Model):
name = models.CharField(max_length=30)
def __unicode__(self):
return self.name
class Entry(models.Model):
votes = models.IntegerField()
category = models.ForeignKey(Category)
participant = models.ForeignKey(Participant)
def __unicode__(self):
output = 'Entry For {0} in Category {1}'.format(self.participant, self.category)
return output
Pretty straightforward. You can add a category an entry and a participant using the default django admin models. This works really well.
Now the question:
In the admin, I want user to click a button and is presented with the listing of all winners for all the categories in the db. I have an idea on how to implement this, where I basically want a user to submit a form in the admin interface. I know the admin interface is implemented via the way all djanog apps are MVC style. But I don't know where I can extend because the adminBaseModel / adminModel acts like a models and view controllers, and url-confs at the same time. It's seems difficult to rewire alot of the internets there.
Can someone point me in the right direction? Just want to simply implement my own view that merely extends the admin view with my own context and method calls.
I hope that was clear. Thanks for all your help guys.

Many-to-many relationships in Django Admin

models:
class Detail(models.Model):
def __unicode__(self):
return self.title
title = models.CharField(max_length=32)
class Cars(models.Model):
def __unicode__(self):
return self.name
name = models.CharField(max_length=32, unique=True)
details = models.ManyToManyField(Detail)
So, every car has a many details - wheels, engine, etc. How to do this: in Django Admin situated Cars menu, in that menu we have a many lines of details (like in tutorial).
In admin I use:
class DetailInline(admin.TabularInline):
model = Detail
extra = 6
class CarsAdmin(admin.ModelAdmin):
inlines = [DetailInline]
But it has error: Detail has no ForeignKey to Cars. How to fix it?
Django does not natively let you add a reverse inline.
i.e. You can have the Detail page contain an inline admin of all the Cars that contain a ForeignKey to that particular Detail. However, the reverse is not natively possible.
There is a workaround though wherein you have to override the admin template a bit. There is a previous SO question about this here: Inline-like solution for Django Admin where Admin contains ForeignKey to other model

Django admin TabularInline - is there a good way of adding a custom html column?

I've got a model (Entry) which contains a simple property:
#property
def image(self):
return str(self.id)+"_"+self.round.season.name+"_"+self.round.theme+"_"+self.person.name
I use this to build the name of a particular image file on disk. So I know that there's going to be an image at /path/to/images/(model.image()).jpg
I can display the raw image property itself within the TabularInline layout on an admin page by adding it to the readonly_fields collection, but how would I go about getting a column which had custom html wrapped around the model property?
e.g.
<img src="/images/{{model.image}}.jpg" />
What you can do is create a method in your TabularInline subclass that returns the HTML you want, then use that method's name in place of image in ImageInline.fields:
from django.utils.safestring import mark_safe
class ImageInline(admin.TabularInline):
...
fields = (..., 'render_image')
readonly_fields = (..., 'render_image')
def render_image(self, obj):
return mark_safe("""<img src="/images/%s.jpg" />""" % obj.image)
According to current Django 1.2+ I got errors "Form does not have such field as render_image". Solution is simple put the render_image function into model.Admin not in your inline form, second thing is fields and readonly_fields settings in your Inline form... So here You have what I've ended up with:
class OfferPropertyInline(admin.TabularInline):
model = OfferProperty
fields=('property_value',)
readonly_fields = ('property_value',)
class OfferAdmin(admin.ModelAdmin):
inlines = [
OfferPropertyInline
]
def property_value(self,obj):
return obj.get_value()
admin.site.register(Offer, OfferAdmin)
Lechup's answer does not work for me, I am using Django 1.11.7. I found this way to work around.
Let say I have 2 tables: Campaign and Article, one campaign has many articles. I want to show the articles when browsing a specific campaign.
Table Article has a column named score, which is a float. I want to round it up to 2 decimal places when viewing in Django admin.
This example shows how you can make a custom column for TabularInline in Django admin.
class Article(models.Model):
title = models.TextField(null=False)
url = models.TextField()
score = models.FloatField(null=True)
def __str__(self):
return self.title
def display_score(self):
if self.score:
return round(self.score, 2)
return self.score
display_score.short_description = 'Score'
class ArticleInline(admin.TabularInline):
model = Article
readonly_fields = ('title', 'url', 'display_score')
fields = ('title', 'url', 'display_score')
class CampaignAdmin(admin.ModelAdmin):
inlines = [ArticleInline]
admin.site.register(Campaign, CampaignAdmin)
#lechup correct except you need:
readonly_fields = ('mycustomfield',)
defined in the Inline for later versions of django (+1.4)

How to access model data when overriding Django admin templates?

sorry if this is an obvious question but I have been searching for a few days and have not been able to come up with a result.
I am creating a simple photo gallery app. There are four galleries, each containing a photo (the photo consists of a 'before' image, 'after' image and caption). I am trying to use django-admin to allow users to click on a gallery and then add photos.
I am using a TabularInline to edit the photos within each gallery. In addition to the default columns on the TabularInline, I would like to add a column that shows a thumbnail preview of the 'before' photo and 'after' photo (I am using easy-thumbnails for this). After much searching, it seems like the best way to do this is to override the django-admin tabularInline.html template and add the column myself - so I created another copy and am trying to edit it now.
What I would like to do is simply reference the Photo object within the Django admin template that I am overriding - but I don't know the appropriate tag to use. I need the reference so I can use it in conjunction with the easy-thumbnails thumbnail tag ... but for the life of me I cannot figure out the template tag that references the object. I have tried iterating through the ModelForm, FormSet, and FieldSet objects but none seem to give me a direct reference to the object.
# models.py
class Gallery(models.Model):
name = models.CharField(max_length=200)
url = models.CharField(max_length=200)
desc = models.TextField()
def __unicode__(self):
return self.name
class Photo(models.Model):
gallery = models.ForeignKey(Gallery)
before = models.ImageField(upload_to='gallery')
after = models.ImageField(upload_to='gallery')
caption = models.CharField(max_length=1000)
order = models.IntegerField(blank = True, null = True)
def __unicode__(self):
return "Photo " + str(self.order)
# admin.py
class GalleryForm(forms.ModelForm):
model = Gallery
class Media:
js = (
'/assets/js/jquery-1.4.2.min.js',
'/assets/js/jquery-ui-1.8.2.custom.min-admin-sortable.js',
'/assets/js/menu-sort.js',
)
class PhotoInline(admin.TabularInline):
model = Photo
extra = 1
template = "admin/tabular-thumbnails.html"
admin.site.register(Gallery,
inlines=[PhotoInline],
form = GalleryForm)
Thanks so much in advance and please let me know if there's any additional information I can offer. I am using Django 1.1
In Django 2.1 {{adminform.form.instance.field_name}} worked for me.
{{ form.instance }} will always be the model instance associated with a modelform, assuming there is one.
(Note that ``{{ formset.instance }}` is the instance of the parent model in an inline formset).