Displaying information from multiple foreign keys in the django admin - django

I've been having some difficulty pulling information from multiple foreign keys and getting that information to display in the django admin. I have four models: Subject, Study, Procedure, and Event. The first three are foreign keys to the last. I want information from each to display in the admin for Event as such: last_name, first_name, ssn, study_desc, procedure_desc, and event_start_time where last_name, first_name_ and ssn are located in the Subject model, study_desc is located in the Study model, procedure_desc is located in the Procedure model and event_start_time is located in the Event model.
Thus far, I've been able to have the information from the Subject model and the Event model display together through use of a Model Form, but I have been unsuccessful in getting additional information from the other two models to display with what I have now. Any suggestions, insights, or alternate methods to use would be much appreciated. The form that I used is below.
class EventForm(ModelForm):
def __init__(self, *args, **kwargs):
super(EventForm, self).__init__(*args, **kwargs)
if self.instance:
self.fields['subject'].queryset = \
Subject.objects.all().order_by('last_name')
class Meta:
model = Event
class EventAdmin(admin.ModelAdmin):
form = EventForm
search_fields = ['subject__last_name','subject__first_name','subject__ssn']
list_display = ['last_name','first_name','ssn','event_start_time']

One option to display information from related objects is to use a callable.
This is exlained in the list_display docs for Django's ModelAdmin.
Also check this question on SO for some detailed examples and discussion.

Related

Load external data into an admin model - DJANGO

Is it possible to load external data into a field for filling in?
Example: A field with for product names. However we already have the names of the products in another location, we just need to list these products within the field in the default django admin. Using resquets.
Thank you very much for your attention.
I think what you're looking for is how to customize the Django Admin, right? Check out this page in the documentation for a more detailed explanation, but here's an example that might help:
from django.contrib import admin
from .models import *
class ProductInline(admin.TabularInline):
model = Product
extra = 0
class OrderAdmin(admin.ModelAdmin):
inlines = [ProductInline]
admin.site.register(Order, OrderAdmin)
admin.site.register(Product)
This will show all of the products attached to a particular order when viewing that order from Django Admin.
You can prepopulate/fill a field in Django Admin with external data source. I guess you have some options defined somewhere outside your Django app and use those options as input for a charfield/integer field.
You can handle filling choices in a seperate Django form or overriding ModelAdmin methods. By creating a seperate form:
filter_choices = depends on your logic for loading external data
class AdminForm(forms.ModelForm):
filter_text = forms.ChoiceField(choices = filter_choices , label="Filter By",
widget=forms.Select(), required=True)
class Meta:
model = YourModel
#admin.register(YourModel)
class YourModelAdmin(admin.ModelAdmin):
form = AdminForm
You can try the 'formfield_for_foreignkey' method of the default ModelAdmin class
Example:
class MyModelAdmin(admin.ModelAdmin):
def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == "car":
kwargs["queryset"] = Car.objects.filter(owner=request.user)
return super().formfield_for_foreignkey(db_field, request, **kwargs)
This example (from the original docs) will populate the 'car' field with only specific values.
Pls note that this method suits a foreinKey. I'm not sure if it fits your requirements.

What is Best practices for Django model ForeignKey unique=True not to be displayed in form?

Is there a best practice for ForeignKey unique=True values not to be displayed in the forms selection choice?
WarehouseBin = models.ForeignKey(WarehouseBin, unique=True)
It is annoying for the users to select options that they are not allowed in model.
Do I have to redefine in the view form values after it was initiated .
form = ***Form(instance=post)
form.fields['WarehouseBin'].queryset =***.objects.exclude(***)
Is there any other way?
The best practice to control the content of the foreign key fields is to override your form __init__() method. That way your form logic is nicely separated from your view, and you can reuse the same form in your view and admin if you want to.
from django.forms import ModelForm
from myapp.models import Article
# Create the form class.
class ArticleForm(ModelForm):
class Meta:
model = Article
fields = ['pub_date', 'headline', 'content', 'reporter']
def __init__(self, *args, **kwargs):
super(ArticleForm, self).__init__(*args, **kwargs)
# fetch only active reporters
self.fields['reporter'].queryset = Repoter.objects.filter(active=True)
For more details see: https://docs.djangoproject.com/en/dev/ref/forms/fields/#fields-which-handle-relationships
BTW, since you are interested in best practices, here's another tip. You shouldn't use camel case for your class fields, but lowercase with words separated with underscore:
warehouse_bin = models.ForeignKey(WarehouseBin, unique=True)
See PEP8 for more details.

Accessing a model variable in Django

Obviously I am new to Django, because I would assume this is relatively simple.
Lets say in my models.py I created a model "User", with two fields, a "username" and a "email" field. In a form called "UserForm", I want to access a list of all the "username"s in the "User" model. This list would then be used to populate a dropdown menu using Select.
I feel like this should be really easy, and I have been looking for some simple way to do it. I can find lots of ways that aren't all inclusive (ie filter(username = "Joe")), but I can't find one that will list all the users.
Any help would be greatly appreciated.
You're looking for a ModelChoiceField. Its queryset property can be populated from an ORM call, getting you all of the Users. Have a look at the section Creating Forms from Models in the docs for more information.
from django.contrib.auth.models import User
class UserForm(forms.ModelForm):
class Meta:
model = # Your model here
def __init__(self, *args, **kwargs):
self.fields['user'] = forms.ModelChoiceField(queryset=User.objects.all())
ForeignKey fields will be automatically shown as ModelChoiceFields, but you can always override the choices if you need.

Django admin site: How does the Add User page work (more fields on edit)?

I was wondering how they made it possible to display more fields in the User page of the Django admin site.
If you create a new User you only have some basic fields to fill in, but if you reopen that user (edit mode) then you see a lot more fields to fill in.
I'm trying to achieve the same, I had a look at the add_form.html template but I can't really get my head around it. I guess I'm looking for a way of specifying different fields = [] sets based on the edit status of the document.
Thanks!
The answer lies in the custom admin class registered for the User model. It overrides a couple of methods on ModelAdmin and checks to see whether the current request is creating a new User (in which case the bare-bones form class for adding accounts is used) or editing an existing one (in which case a full form is shown).
Here's my try. When I try to create a new item (Add) it shows only certain fields but then when I hit save it returns an error:
DoesNotExist
in /Library/Python/2.6/site-packages/django/db/models/fields/related.py in get, line 288
admin.py
from django.contrib import admin
from myapp.catalog.models import Model
from myapp.catalog.forms import ProductAdminForm, ProductAddForm
class ProductAdmin(admin.ModelAdmin):
form = ProductAdminForm
#...
add_form = ProductAddForm
def get_form(self, request, obj=None, **kwargs):
defaults = {}
if obj is None:
defaults.update({
'form': self.add_form,
})
defaults.update(kwargs)
return super(ProductAdmin, self).get_form(request, obj, **defaults)
forms.py
from myapp.catalog.models import Product
class ProductAdminForm(forms.ModelForm):
class Meta:
model = Product
#...
class ProductAddForm(forms.ModelForm):
class Meta:
model = Product
fields = ("model", "colour",)

Django Interleaving UserProfile with Profile in Admin

I have a User Profile which is currently shown in the Admin via a Stacked Inline. However because I have fields such as last_name_prefix and last_name_suffix (for foreign names such as Piet van Dijk to cover proper sorting by last name) I would like to be able interleave the user profile fields with the normal change user fields. So in the Change User admin interface it would appear like this:
First Name:
Last Name Prefix:
Last Name
Last Name Suffix:
I have tried this solution: http://groups.google.com/group/django-users/browse_thread/thread/bf7f2a0576e4afd1/5e3c1e98c0c2a5b1. But that just created extra fields in the user form that weren't actually coming from the user profile (they stayed empty even though they should get values from the user profile).
Could someone explain to me if this could be done and how?
Thanks very much!
I'm pretty sure you'd need to overwrite normal User admin.
What I would actually do is create a special forms.ModelForm for UserProfile called, say UserProfileAdminForm which included fields from the User model as well. Then you'd register UserProfile for admin and the save function for the UserProfileAdminForm would capture the user-specific fields and either create or update the User record (This is left as an exercise to the OP).
More info
When I say add more fields to a form, I mean manually add them:
class UserProfileAdminForm(forms.ModelForm):
username = forms.CharField(...)
email = forms.EmailField(...)
first_name = ...
last_name = ...
def __init__(self, *args, **kwargs):
super(UserProfileAdminForm, self).__init__(*args, **kwargs)
profile = kwargs.get('instance', None)
if profile and profile.user:
self.user = profile.user
self.fields['username'].initial = self.user.username
self.fields['last_name'].initial = ...
...
class Meta:
model = UserProfile
This question has been solved by the new Django version 1.5: https://docs.djangoproject.com/en/1.5/topics/auth/customizing/#auth-custom-user.