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

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.

Related

Hide Model Property from Django admin and set Its Value Manually

I want to hide a column from django admin and set its value from session.
In simple words i want to set a property of a model from session and don't want a field in admin for that column.
Can someone help me?
You can mark the field as read-only but still have it visible in the admin, or completely exclude it.
class MyModel(models.Model):
field1 = models.CharField(max_length=20) # this is editable
field2 = models.CharField(max_length=20, editable=False) # this is not
or
#admin.register(MyModel)
class MyModelAdmin(admin.ModelAdmin):
exclude = ['field2']
If you're using a custom model form in the admin, just don't include the field in the fields attribute.
As far as I remember there are a lot of ways to do this, with the fields attribute on Meta you can hide or select which fields to show.
check This example

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.)

Django admin filter

I've got multiple instances of a model, and each instance has a related email address. However, several instances have the same connected email address but when I put filter['email'] into my admin.py, I get a long list of the instances' emails, i.e. multiple copies of the same email in several cases.
Is there a way I can remove emails being listed multiple times? Or a way of customising the filter view into something a little nicer? (drop down menu maybe?)
I don't have a ManyToManyField relationship currently, or anything like that. I just have instances in my database with the fields name and email. My models.py looks like this:
import ldapdb.models
from ldapdb.models.fields import CharField, IntegerField, ListField
class Item(ldapdb.models.Model):
item = CharField(db_column='item', max_length=30, primary_key=True, unique=True)
email = CharField(db_column='mail', max_length=20)
My admin.py looks like so:
from items.models import Item
from django.contrib import admin
class ItemAdmin(admin.ModelAdmin):
readonly_fields = ('email',)
list_display = ('item', 'email')
list_filter = ['email']
search_fields = ['item']
admin.site.register(Item, ItemAdmin)
Obviously I've been looking at https://docs.djangoproject.com/en/1.3/ref/contrib/admin/ but I can't really see much by the way of customising my admin's filter view.
Can you post some of your code? I'm not entirely sure I understood the relationship between the instances to your email - is it an email field? a ForeighKey to a different model? how is there more than one if it's not a ManyToMany or similar relationship? And how is the filtering done in the admin?
EDIT
Ok now I understand the problem. What you want is not possible. See for the django admin site the fact that they are the same email doesn't matter because it's still a different object. There's no way around that without either specifying that field to be unique or messing with the admin site code.
A better solution would be to configure the email as searchable in the admin model and then when you search for email example#example.com it would bring all matches back.
Another good solution is to make email a different model and link it to the Item model through a ManyToMany relationship. Then you create an EmailAdmin with a method that shows you all related items for each email.
It all depends on what you actually need. Ultimately you might want to write your own view or mess around with the admin site to modify it to what you need.
Also, you might want to change the email from CharField to EmailField. Hope this helps!

How to show date_created in Django admin

I have a model created in Django 1.5 as below:
class Number(models.Model):
phone_number = models.CharField("Phone Number", max_length=10, unique=True)
I set up Django admin as below:
from django.contrib import admin
from demo.models import Message, Number, Relationship, SmsLog
class NumberAdmin(admin.ModelAdmin):
search_fields = ['phone_number']
admin.site.register(Number, NumberAdmin)
I believe Django add "date_created" column to the database automatically (because I know it sorts the data entries by creation time in admin console). Is there a way to view those time/dates in admin console? The closest I have go to is Django tutorial and StackOverflow ,but I do not want to create another column on my own (pub_date in Django official tutorial's example) and add it if possible. Is there a way to do it and if so, could someone show me how to? Thank you!
Django does not automatically add a date_created column. If you want to track the creation date, you have to declare it in your model.
You may be getting the illusion that it does because if you do not specify a sort order in the model or in the admin class for the model, it will default to sorting by primary key, which will increase according to the order the model instances were created.

Filter foreignkey choices in Admin changelist view

I got two models which are related via ForeignKey in Django. (I am using Django 1.3)
Class Person(models.Model):
# some fields here like name, gender, etc...
Class Course(models.Model):
# some fields here
contact = models.ForeignKey(Person, blank=True, null=True)
In the admin changelist view for the Courses I want to be able to filter the Courses by the ForeignKey contact. In the admin.py i got:
class CourseAdmin(admin.ModelAdmin):
list_filter = ('contact',)
This work very well. I can filter the Courses by all available Contacts. Now I would like to display only those contacts that actually have a Course attached to them.
I read here on SO to implement CustomFilters by creating a custom FilterSpec. I dont know wheter this is the right direction, because I only need to further filter the queryset that is used to display the choices for the contacts.
In the shell I get the desired queryset by this:
contacts=Person.objects.filter(course__in=Course.objects.all()).distinct()
I already read that you can easily achieve this in 1.4, but I am still bound to 1.3
Can someone please point me into the right direction? Thank you!
Django 1.3 also supports Filters, but the filter classes were moved/renamed in 1.4. And using a FilterSpec is the way to achieve your goal. You not only need to filter the queryset, but to handle properly the applied filter from QueryString. So go ahead with filters. Here is a very good snippet, that handles the FK filtering, and has decent options: http://djangosnippets.org/snippets/2260/