displaylist of children in parent model one-to-many - python

I am learning django admin, i have to models with a one-to-many relation between them.
I got something like Manufacturer model where i can add different car manufacturers, and Car model for adding cars. In my django admin page i want to be able to display_list of all cars manfuctred by say manufacturer1 when i click on manufacturer1 entry.
I have found a trick by using Inline model in manufacturer admin model, the problem is that it loads every entry in the database and it takes some time as it's a big table.
Is there any method else to do that or do i have to create a new template ?
EDIT:
The goal is not to load every Car that is FK to Manufacturer1 like with InlineModelAdmin but to get the same display as with display_list with results split in pages

Answer for your updated question:
the way to do it could be by using ProxyModels and overriding ModelAdmin.queryset
You extend the Car model via FordCar, GMCar and use proxy=True in the Meta class, for both those.
Then you can register seperate admins for each of FordCar and GMCar and override the queryset method in each of those ModelAdmin to filter for the respective manufacturer.
Ex:
class FordCarAdmin(admin.ModelAdmin)
list_display = fields = ['name','model','engine']
def queryset(self,request):
qs = super(MyModelAdmin, self).queryset(request)
return qs.filter(manufacturer__name='Ford')
admin.site.register(FordCar,FordCarAdmin)

You have two options.
The easiest approach is to look at the relationship in reverse. Instead of going to a manufacturer change form and seeing all their cars. Go to the cars changelist and filter by manufacturer. You'll have to set the list_filter attribute on the car ModelAdmin to include manufacturer.
Option two, is going to be a huge pain, but you can override change_view on the manufacturer ModelAdmin to add the list of that manufacturer's cars to extra_context. Then, you'll have to override the admin template at 'templates/admin/yourapp/manufacturer/change_form.html'. You can then add to that template to produce the kind of list you're looking for using the list of cars you passed into extra_context, drawing on 'django/contrib/admin/templates/change_list.html' for inspiration.
Give the Django docs on the Admin a good thorough read. There's actually a wealth of info in there.

You don't need any hack. Django admin displays only Cars that have a FK to Manufacturer1, when you select Manufacturer1, as long as you have used the InlineModelAdmin right and as intended.

Related

How to add objects to a different model when using a form in Django?

I have a few forms that retrieve objects through a ForeignKey, e.g. Flight, Trip.
So, for example, when someone tries to create a new Trip, they can choose an Hotel from a dropdown.
My question is: how can we, on the Trip form, add an Hotel. Just like when using Django's own admin dashboard, where you get a plus sign, and you can add a new Hotel while creating a Trip.
Edit:
Hotel is a ForeignKey on the Trip model.
And I am using ModelForm.
The objective is that you can either choose an existing Hotel or create a new one while creating a Trip.
I think you are looking for forms.ModelChoiceField.
It is used this way:
hotel = forms.ModelChoiceField(
queryset=Hotel.objects.all() # or whatever queryset you want to use
# Rest of the configuration
)
If I'm not mistaken, it will create an Html Select tag having options with pk of each Hotel object as the value. To specify the inner text of each option, you have to define the following method for the Hotel class:
def __str__(self):
return self.name # or whatever needed
If you indeed were looking for this I have to discourage you from using it if you are building a production-grade website/app. A better (and obviously more elaborate) approach is to get the query set of Hotels, serialize them to JSON, create a card/row/widget for each hotel for the user to search and select. However, it is a quick and handy way of managing small projects.

how to handle select boxes in django admin with large amount of records

my app has grown so that that drop downs in the django admin have 100,000s of options. I can't even open my admin anymore because of its load on the database, not too mention I wouldn't be able to find an option in the select box.
Does django have an autocomplete option?
What is the best option for handling big data in django admin?
Django 2.0 has introduced a new feature on the admin site, called autocomplete_fields, which is helpful for models with foreign keys. It replaces the normal <select> element with an autocomplete element:
class QuestionAdmin(admin.ModelAdmin):
ordering = ['date_created']
search_fields = ['question_text']
class ChoiceAdmin(admin.ModelAdmin):
autocomplete_fields = ['question']
Here's a screenshot of the element:
Use raw_id_fields, like this:
class SomeModelAdmin(admin.ModelAdmin):
raw_id_fields = ('problematic_field', )
You can read more about this, here:
https://docs.djangoproject.com/en/1.11/ref/contrib/admin/#django.contrib.admin.ModelAdmin.raw_id_fields
Basically - it will change the select boxes with raw id field with a lens icon - which open another window to make changes.
There is many solutions to your problem out there but here is two ways I consider as viable:
If you need a built-in solution where you don't want to involve an external library, raw_id_fields may help you. This is from the documentation:
By default, Django’s admin uses a select-box interface () for
fields that are ForeignKey. Sometimes you don’t want to incur the
overhead of having to select all the related instances to display in
the drop-down.
raw_id_fields is a list of fields you would like to change into an
Input widget for either a ForeignKey or ManyToManyField:
class ArticleAdmin(admin.ModelAdmin):
raw_id_fields = ("newspaper",)
Use an auto-complete widget. There is ton of existing packages, see this list. Be careful to look which one has recent commits, it will give you an idea of the community awarness.

In the Django admin page, when creating a new instance of a model, is there a way to disallow certain foreign key instances from appearing as choices?

Let's say I have three models: Restaurant, MenuCategory(breakfast, lunch, etc.), and FoodItem. FoodItem has two foreign key fields, one to Restaurant, and the other to MenuCategory. MenuCategory has one foreign key field, to Restaurant.
When I try to create a new FoodItem via the Django admin page, I am asked to select a Restaurant, and MenuCategory, and some other unrelated fields such as the name of the food or the description. However, when I look through the choices for MenuCategory, I can see every possible MenuCategory that exists, even those that do not belong to the Restaurant that I have currently chosen for the FoodItem about to be created.
When I am making a new FoodItem, is there a way to get the admin page to only display the MenuCategories that belong to the current Restaurant I have selected?
Sounds like you just need to restrict the queryset used in dropdown field.
https://docs.djangoproject.com/en/1.9/ref/contrib/admin/#django.contrib.admin.ModelAdmin.get_queryset
I've also pasted the docs here.
ModelAdmin.get_queryset(request)
The get_queryset method on a ModelAdmin returns a QuerySet of all
model instances that can be edited by the admin site. One use case for
overriding this method is to show objects owned by the logged-in user:
class MyModelAdmin(admin.ModelAdmin):
def get_queryset(self, request):
qs = super(MyModelAdmin, self).get_queryset(request)
if request.user.is_superuser:
return qs
return qs.filter(author=request.user)
Essentially you would just restrict to the that you want to display only.

Django Admin Forms with additional fields in ManyToMany relations

I have 2 Entities with a ManyToMany Relation and some additional fields, here you can find an example diagram:
I created all models following the documentation and everything works, but I would also manage MTM relations using django admin without use another form to create a new "WheelsCar" row that links togheter a car and a wheel. Is it possible? How?
Admin use case:
I click on add new Car
I select one of the wheels, filling the additional fields (position, holes...)
Iterate step 2
Save a New Car
I got it, I have to use Inline Fields!
Doc: https://docs.djangoproject.com/en/dev/ref/contrib/admin/#working-with-many-to-many-intermediary-models

Formatting inline many-to-many related models presented in django admin

I've got two django models (simplified):
class Product(models.Model):
name = models.TextField()
price = models.IntegerField()
class Invoice(models.Model):
company = models.TextField()
customer = models.TextField()
products = models.ManyToManyField(Product)
I would like to see the relevant products as a nice table (of product fields) in an Invoice page in admin and be able to link to the individual respective Product pages.
My first thought was using the admin's inline - but django used a select box widget per related Product. This isn't linked to the Product pages, and also as I have thousands of products, and each select box independently downloads all the product names, it quickly becomes unreasonably slow.
So I turned to using ModelAdmin.filter_horizontal as suggested here, which used a single instance of a different widget, where you have a list of all Products and another list of related Products and you can add\remove products in the later from the former. This solved the slowness, but it still doesn't show the relevant Product fields, and it ain't linkable.
So, what should I do? tweak views? override ModelForms? I Googled around and couldn't find any example of such code...
Maybe it is not what you expect but I would introduce InvoiceItem model which would link Invoice to Product. So you would have 2x 1:n instead of m:n relation. Then use inline custom form for InvoiceItem and raw_id_fields in that form for Product choice.
In InvoiceItem form then you could add readonly fields that would display values you need to display. You will have to provide data for these fields in Form's init reading them from InvoiceItem instance. Or you could also derive from raw_id_field widget and in render method of this widget append some additional data from the product model?
This is an old question, but I have related to it today.
You can find the answer here - https://blog.ionelmc.ro/2012/01/19/tweaks-for-making-django-admin-faster/
The code:
class MyAdmin(admin.TabularInline):
fields = 'myfield',
def formfield_for_dbfield(self, db_field, **kwargs):
formfield = super(MyAdmin, self).formfield_for_dbfield(db_field, **kwargs)
if db_field.name == 'myfield':
# dirty trick so queryset is evaluated and cached in .choices
formfield.choices = formfield.choices
return formfield
This can cut your waiting times from anything like 5 minutes to around 15 seconds.

Categories

Resources