Django Admin Forms with additional fields in ManyToMany relations - python

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

Related

How to create an extended User Object in Django?

I created a model ExtendedUser to extend the User Django built-in model class using the approach described in the official documentation:
https://docs.djangoproject.com/en/3.2/topics/auth/customizing/#extending-the-existing-user-model
so that I can benefit from the existing authentication features provided by Django.
That works all fine however I wonder now, whenever I want to create a new ExtendedUser, that means for every ExtendedUser, I also need to create an original User to fullfill the one-to-one relationship?
Or what else does it mean the following:
Assuming an existing Employee Fred Smith who has both a User and Employee model, you can access the related information using Django’s
standard related model conventions[...]
In a script to create objects, would this mean the following:
u1 = User.objects.create_user(username="u_1", email="u_1#abc.com", password="pw_u_1")
ext_u_1 = ExtendedUser.objects.create(id=u1.id, user=u1, prop_1="XYZ")
where
class ExtendedUser(models.Model):
user = models.OneToOneField(User, ...)
# More properties...
Yes, if you extend using OneToOne field, it will require to create both objects i.e. User as well as ExtendedUser to fulfil the one to one relationship.
But I would suggest to not use OneToOne field instead override the AbstractUser model provided by Django to create the ExtendedUserModel, even if you don't need anything extra in ExtendedUserModel now. It will help you to add any new fields, methods easily to your user model in future as well as you won't be needed to create two object for a single User.
Same has been suggested in Django docs as well. Reference:- https://docs.djangoproject.com/en/3.2/topics/auth/customizing/#using-a-custom-user-model-when-starting-a-project

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.

Django admin - Create a complex filter on User model

I have a field Foo with a ForeignKey that points to User. I need to create filter in the admin that only displays User that have at least one Foo. This would be easy with the development version of Django, but I am stuck with the 1.3.
I have seen here how to add a custom filter using the undocumented FilterSpec class. My problem is that it requires to modify the User model. I could inherit from User, but I already ave a setup where additional data is put into a Profile model wiith a one-to.one link to User.
Is there a less intrusive way to add a custom filter to the User model?
You can actually use the foreign key relation backwards in an ORM query.
User.objects.filter(foo__isnull=False)

displaylist of children in parent model one-to-many

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.

Improving Performance of Django ForeignKey Fields in Admin

By default, Django's admin renders ForeignKey fields in admin as a select field, listing every record in the foreign table as an option. In one admin-accessible model, I'm referencing the User model as a ForeignKey, and since I have thousands of users Django is populating the select with thousands of options. This is causing the admin page to load incredibly slowly, and the select is not very useful since it can take a while to scroll through thousands of options to find the one you want.
What's the best way to change the rendering of this field in order to improve page load and usability? I'd like the select field to be replaced with some sort of button to launch a search form popup, or a text field that searches keywords via Ajax to find the Id for the specific User they want to associate. Does admin have anything like this builtin, or would I have to write this from scratch?
Add raw_id_fields to your model to only show the ID instead of a dropdown.
You're right, Cerin, the cause of the slowdown is because Django is populating the <select> element with too many options. You might want to use an autocomplete element instead.
Interestingly, Django 2.0 has introduced a new feature on the admin site, called autocomplete_fields, which I think you will find useful in this case. It uses AJAX.
class ExampleAdmin(models.ModelAdmin):
autocomplete_fields = ['example_field_user']
You can use one of the few autocomplete apps for Django. Check them at Django Packages.
There's also django-extensions that have ForeignKeyAutocompleteAdmin that fit your needs pretty well.
Another option is to add readonly_fields instead of raw_id_fields

Categories

Resources