Django ManyToManyField order is not being kept - django

I have two models: Customer and Resources. Customer has a ManyToManyField to Resources. I add the relations from the admin panel e.g.:
Customer_1 -> Resource_8, Resource_5, Resource_14
The main problem is that I want to insert these relationships in that exact order: resource 8, 5 and 14. But when the admin form is submitted, it saves the relations as follows:
Customer_1 -> Resource_5, Resource_8, Resource_14
I assume that it is ordering the resources by its ID and not respecting the order they were submitted.
My question is, how do I change this behaviour, so that it always respect the order which was submitted on the admin site?

Django doesn't support ordering in M2M fields, you will need to alter the way your model is defined, specifically you will need to create a through table and use a custom ordering field for it.

Related

Choose a specific manager for a related field for a model

I am in a situation where I need to use a custom manager for a related field which is different from the base_manager for the related fields. Let's say that I have a model Item which is in one to many relation with another model Purchase. Now, Item has 2 managers:
objects = ItemManager() #which by default excludes the out_of_stock=True items
complete = CompleteItemManager() #which gives all the items.
For all the other models related to Item, ItemManager is the default one. But in Purchase, I would want to use the CompleteItemManager for the related Item.
So let's say there was once a purchase for an item which is now has out_of_stock=True and we just have the id of that purchase say old_purchase_id, now if try to run the below query:
purchase = Purchase.objects.filter(id=old_purchase_id) # gives error
It would give an error like "Item matching query does not exist" as the manager being used for the related items is ItemManager which excludes such out of stock items.
What can be done in that case? Ideally I would want something to override the manager to be used for a given related field per model, so that even if all other models use ItemManager to resolve item fields, the Purchase Model still uses the CompleteItemManager for its relations with Item.
When accessing a reverse relation you can specify a custom manager to use by calling the related_name and passing the custom manager by name
purchase.item_set.all() # Uses ItemManager
purchase.item_set(manager='complete').all() # Uses CompleteItemManager
Here's how I did it.
I made a CustomForwardManyToOneDescriptor which would just pick the manager named complete for the related model. And used that descriptor in a CustomForeignKey as the forward_related_accessor_class.
class CustomForwardManyToOneDescriptor(ForwardManyToOneDescriptor):
def get_queryset(self, **hints):
related_model = self.field.remote_field.model
return related_model.complete.db_manager(hints=hints).all()
class CustomForeignKey(models.ForeignKey):
forward_related_accessor_class = CustomForwardManyToOneDescriptor
Now using the CustomForeignKey instead of ForeignKey to create OneToMany relation with a model would make that model use the complete manager for the foreign key field no matter what the default related manager is.

Where is ID saved in django ModelAdmin autocomplete_fields?

I am rewriting some administration interface to django 2.2, currently using django autocomplete_fields admin feature. Simply said I have ModelAdmin object OrderAdmin, which has nested TabularInline ProductAdmin: variable-length table of products which might be added to order. Each of these ProductAdmin holders just contains ForeignKey to actual product class, with some other attributes.
Now I wonder: where does django store id - ForeignKey - of item selected with autocomplete field? It doesn't mark OPTION in selectbox as selected, and although there is suspicious hidden input field with #cashregisterproduct_set-0-id on page, it doesn't have any value. Or is there some special way how to access it? I was thinking about adding id to __str__ method of model and parsing, but thats just ugly.
Thanks for tip.
EDIT: to make it 100% clear, where from does django get ForeignKey of object selected through autoselect_field, when creating new object from ModelAdmin?
I got misguided thinking that this is managed by django. Selected data might be accessed by using select2 framework:
selected_value = $('.myselectbox').select2().val();
related: https://stackoverflow.com/a/47451658/16268461

Wagtail page model: foreign key entity + multiple parameters

i'm using Wagtail CMS to create product catalogue. I created basic page type for product:
class Product(Page):
It has basic fields like title, description, image aso. But i need "something special":
There is special part available in many variants and each product can have some of them. So I created another model, very simple by:
#register_snippet
class Variant(models.Model):
to store all variants. Variant has name and image. There are about 200 products and 30 variants.
My problem is and I don't know how to manage in Wagtail two tasks:
to link Product with Variants (foreign key) with many-to-many relation to select product related variants in same page as other page entities
each relations has additional parameters (2 params) which are relation specific (material and diameter) and again I haven't found how to display and manage such relations in page editor
I know that Django can handle it by inline formsets (django admin supports it out of box), but is there Wagtail-way to get this done and editable by Wagtail editor? I prefer to manage whole product in the same place, not relations separated in django-admin.
Thanks for any help or advice.
InlinePanel is the Wagtail equivalent of Django admin's inline formsets. An example of this is given in Wagtail's tutorial: https://docs.wagtail.io/en/stable/getting_started/tutorial.html#images
In this case, it's setting up a many-to-many relation between pages and images, with an additional parameter (caption) on the relation; your Product -> Variant relation could be set up in the same way.

How to extend or increment the model field dynamically in django admin?

In my Django admin i want to add the URLField box dynamically.that means In my model i have one URLField for that model,In future the links will be added more than one.but i have only one URLField.I wannt it should be flexible to add multiple URLFields.
Note: Inline Model will solve this. but,For the single field it should be extended as a Foreignkey also it occupies lot of time for that optional operation.
I am expecting the custom support to add the model fields only in django admin?
The attached file will expect something!
One approach is to limit the inline formset to 0 extra objects if there is already a record present for that foreign key field by setting the "extra" property: https://docs.djangoproject.com/en/1.3/ref/contrib/admin/#inlinemodeladmin-options

django admin inlines (and nested inlines) : how can I get this functionality?

I'm a little confused as to why this sort of functionality isn't default in the admin, but maybe someone can give me a few hinters to how to go about it.
I have a projects application which keeps track of projects and is to be edited through the admin. Each project has numerous ForeignKey related models (links, flatpages, video, image etc.) that could be placed as inlines within the project admin.
(One or two models have nested inlines, so they don't display in the admin (this and this ticket deal with this) )
Instead of being able to edit these models inline on the project admin (which gets messy and difficult to use), I would love a list of all the current instances of that related model, and simple add/edit button for each model which opens a popup with that model's form.
Project Admin:
- Normal Fields
- Links:
-Link 1 (edit)
-Link 2 (edit)
+ add link <- popup
- Images:
-Image 1 (edit)
-Image 2 (edit)
+ add image <- popup
so on. How would I go about writing this? I only need to do it for one section/model of the admin panel so I don't think writing my own Crud backend is necessary.
Thanks
I implemented something like this in an application once, but since django-admin doesnt support nested inlines (by which i mean inlines within inlines), i followed a slightly different approach. The use case was that you had an invoice (with a few inline attributes) and u had reciepts (again with inline attributes). Reciepts had a foreign key to the invoice model (basically a reciept was part payment of the invoice).
I implemented it by adding a field to the invoice list view which linked to a filtered reciept list view.
So in the invoice admin, there would be:
def admin_view_receipts(self, object):
url = urlresolvers.reverse('admin:invoice_%s_changelist'%'receipt')
params = urllib.urlencode({'invoice__id__exact': object.id})
return 'Receipts' % (url, params)
admin_view_receipts.allow_tags = True
admin_view_receipts.short_description = 'Receipts'
This gives you a link in the list view that takes you to another list view, but filtered by foreignkey. Now you can have inlines for both models and easy access to the related models.