Display related foreign keys in the parent model in Django admin - django

I'm using PostgreSQL for the DB.
I have two models:
Project - can contain N Assets.
Asset - has a Foreign Key field that points to a Project. An Asset is related to 1 Project.
I want the user to be able to set the order of the Assets of a Project in the Django Admin in a handy way like ordering a list in the edit Project screen.
The order of the Assets is important in my business logic, but I don't want the user to set the order for each individual Asset (just to improve UX).
Is there a way to show a field in the Project admin screen that lists all the Assets that are related to the project and allows the user to order them as he wishes?
I did not find any solution to this other than adding a new field in the Asset modal to specify the order and handling the logic by myself (which is expected), however, I don't want it to be a field that has to be changed manually in each individual Asset.

By assuming your model structure:
Add a related_name in your Asset model
models.py:
# imports ..
class Project(model.Models):
# other fields
class Asset(model.Models):
project_linked = models.ForeignKey(Project, related_name='related_assets', on_delete=models.CASCADE)
Then use that to list and oder projects in the admin project listing page:
admin.py:
from django.contrib import admin
# import the Project model
class Projectadmin(admin.ModelAdmin):
list_display = ["related_assets"] # add any other desired fields from the Project model
ordering = ["any_fields from model"] # replace the field with your preference
admin.site.register(Project, Projectadmin)
Upon specifying ordering list, the admin will have a toggle button on top of specified fields to re-order them.

Related

Is there a django admin widget that allows the admin to sort model objects by fields values?

I am building an app in Django.
I found there is a very easy way to integrate a widget into django admin that allows the admin to filter model objects by fields values. That is achieved by including the line
list_filter = ['field_to_filter_by_its_values']
into the class mymodelAdmin(ImportExportModelAdmin) in admin.py, as shown below
class target_area_history_dataAdmin(ImportExportModelAdmin):
resource_class = target_area_history_dataResource
list_filter = ['Target_area_input_data__Name']
admin.site.register(target_area_history_data, target_area_history_dataAdmin)
Now, instead of integrate a widget to filter my model objects by that field, is there a way to integrate a widget to sort my model objects by that field?
Note: I am using Django Import-Export in my model.
I'll suggest you use django-treebeard. This allows you to view tree nodes hierarchically in the administration interface, with interface features dependent upon the tree algorithm used.
# admin.py
from django.contrib import admin
from treebeard.admin import TreeAdmin
from .models import Category
class CategoryAdmin(TreeAdmin):
list_display = ("title", "created", "modified",)
list_filter = ("created",)
admin.site.register(Category, CategoryAdmin)
What's cool about this is that you can not only sort (by clicking the header row) but also drag things around, as shown in this image.
I recommend you using the grapelli admin interface that allows what you need and a bit more. here you have the grapelli project page and the https://github.com/sehmaschine/django-grappelli.
It's a well documented package and is plug and play for what you need. It also gives a fresh face to Django Admin and is compatible with Django import/export package.

Adding Q Lookup to Wagtail CMS Snippets

I am building out a restaurant website and using Wagtail CMS Snippets for the owner to manage menu items. The list of menu items are getting rather long and I was wondering if there is any way to add a search input field to the Snippets admin window? Below is an annotated screenshot for visual reference. Thank you.
This can easily be solved by using Wagtail's ModelAdmin module (http://docs.wagtail.io/en/v1.8.1/reference/contrib/modeladmin/), all you need is to add this piece of code to your wagtail_hooks.py file:
from wagtail.contrib.modeladmin.options import (
ModelAdmin, modeladmin_register)
from .models import Product
class ProductAdmin(ModelAdmin):
model = Product
menu_label = 'Product' # ditch this to use verbose_name_plural from model
menu_icon = 'date' # change as required
menu_order = 200 # will put in 3rd place (000 being 1st, 100 2nd)
add_to_settings_menu = False # or True to add your model to the Settings sub-menu
exclude_from_explorer = False # or True to exclude pages of this type from Wagtail's explorer view
list_display = ('title', 'example_field2', 'example_field3', 'live')
list_filter = ('live', 'example_field2', 'example_field3')
search_fields = ('title',)
# Now you just need to register your customised ModelAdmin class with Wagtail
modeladmin_register(ProductAdmin)
It'll create a separate menu entry for your Products model that's customisable much like default Django Admin listing. Which means you can easily add different filters and sorters to a listing.
This is a very powerful feature and I myself don't show clients the "Snippets" section at all; it's just too simple and ugly. Instead, I create a separate ModelAdmin per snippet and this gives me the power of customisation.
The search bar will appear automatically once you set up your model to be indexed with the search system. You can do this by inheriting from the wagtail.wagtailsearch.index.Indexed class and defining a search_fields list on your model, as described here: http://docs.wagtail.io/en/v1.8.1/topics/search/indexing.html#wagtailsearch-indexing-models
(Note that if you're using Elasticsearch, you'll also need to run ./manage.py update_index to add the items to the search index.)

admin site doesn't show object fields

I have a model with a PointField from django.contrib.gis.db.models . This somehow doesn't let the admin site show the objects with a nice table of fields and values. Instead it displays one field named after the model name. The values are just a bunch of ' object'. With the name of the model. If I click the object I can edit it fine. It would be nice however to be able to filter and see the field values at the admin/ page itself.
Since PointField does not have a __unicode__ attribute, for the proper name to show up, you can register a new admin model object.
Now, in the admin's list_display,
class PointFieldAdmin(admin.ModelAdmin):
list_display = ('name', 'field_x', 'field_y', ...)
admin.register(PointField, PointFieldAdmin)
More on admin models registering here

Django Project/Apps Layout - Correct way?

I'm creating a simple project in Django to further my knowledge of it and Python, essentially just going to store bookmarks and tags, both will have views, and there will be 3 models:
Tag
Bookmark
Bookmark_Tag (relationships)
I read the "Projects vs Apps" panel in the django documentation, but I'm still unsure of how to lay it out, right now it's all within one Bookmark App, should there be a seperate app for Bookmarks and a seperate app for Tags, and if so, where does the model for the relationships live?
Thanks!
No, you don't need a separate app for each. They're closely related, and it sounds like together they define your app, not separately. If later, you added another functionality to your site that used the same database and settings but didn't share much else with your current app, that would be another app in the same project.
See Django project models.py versus app models.py and Django: "projects" vs "apps" on this site as well as Django tips: laying out an application for some more guidelines.
If Bookmarks and Tags have a many-to-many relationship, and you need to add extra fields to that relationship (other than just the ids of the related objects) you can use a ManyToManyField and set the through table:
class Bookmark(models.Model):
# whatever fields you need on Bookmark
tags = models.ManyToManyField('Tag', through = 'BookmarkTag')
class Tag(models.Model):
# whatever fields you need on Tag
pass
class BookmarkTag(models.Model):
bookmark = models.ForeignKey(Bookmark)
tag = models.ForeignKey(Tag)
# whatever additional fields you need on the relationship
See the Django docs on Extra fields on many-to-many relationships for more info.

Django admin: search for foreign key objects rather than <select>?

My model looks like this:
class Asset(models.Model):
serial_number = models.CharField(max_length=100, unique=True)
asset_tag = models.CharField(max_length=100, unique=True)
class WorkOrder(models.Model):
asset = models.ForeignKey(Asset)
Essentially, a work order is submitted and then an admin assigns an asset to the work order. The asset_tag field is a barcode that we can scan in. When editing the work order in the Django admin, by default the asset field is displayed as a <select> widget. What we want to be able to do is have a search field so that we can scan the asset tag and then search for the right asset in the DB to associate with the work order.
I know you can customize the Django admin foreign key to a hard coded query, but I can't figure out how to get it so it does a search based on a field on the admin page.
Did you take a look at raw_id_fields?
It should be pretty to close to what you're after.
If you are using Django >= 2.0, you can take advantage of a feature called autocomplete_fields. You must define search_fields on the related object’s ModelAdmin because the autocomplete search uses it.
Since you have a ForeignKey relationship to Asset in WorkOrder, in the admin.py of your app add the following:
from django.contrib import admin
#admin.register(Asset)
class AssetAdmin(admin.ModelAdmin):
search_fields = ["serial_number", "asset_tag"]
#admin.register(WorkOrder)
class WorkOrderAdmin(admin.ModelAdmin):
autocomplete_fields = ["asset"]
Add the fields you want to use for searching to search_fields, and add define autocomplete_fields as shown in the code above.
Now you can use the autocomplete_fields from django 2.0.
It's quite neat.