Hi Mike, Thanks a lot for your feedback. Your situation is quiet different from mine, BUT the way you override change_view and the related template will certainly help me to achieve what I need. ...and getting rid of dirty and unnecessary ajax calls.
I keep you posted. Thx. Karim Le vendredi 1 mars 2019 00:06:40 UTC+1, Mike Dewhirst a écrit : > > On 28/02/2019 9:46 pm, [email protected] <javascript:> wrote: > > Hi, > > I'm currently struggling with a custom ModelAdmin. > > > Karim > > I haven't tried to fully understand your use case. However, this is what I > think your process could be if you do not wish to ajax it ... > > 1. Override the model save() method to call a model method which detects > your trigger scenario and calls the code you wish to execute to collect all > the data you wish to display. This might be in the parent model or the m2m > 'through' model. Unlikely to be in the child model. > > 2. Write a Form to reveal the data you wish to display. It probably needs > to be a ModelForm > > 3. Write a template for the data including any hidden fields for object > pks and additionally consider calling {{ block.super }} to display > inherited stuff if you are extending another template and using the same > block. When I first started to work all this out I was able to get my form > to appear at the top of the ModelAdmin form using block.super and spent a > bit of time hiding the big red [Delete] button because it was too close to > my big blue [Pay now] button. However, as I got deeper into it I somehow > lost that and never got it back. I was so pleased with getting it working > eventually that I persuaded myself I didn't really want it on the same page > anyway. Your mileage may vary :) I think you need to hard-code the form in > the ModelAdmin to get it appearing above everything else. > > 4. Write any necessary urls > > 5. Write a view to manipulate your data, based on the request and your form > > 6. Get the Admin to display it on demand. The first line of the > change_view() method below initialises the ModelAdmin to do absolutely > nothing different than usual. Nothing will happen unless the trigger is > detected. Then finally call to super to resume the normal course of events > when your code is complete. What follows is my own recent experience. The > comments should tell you more than the code > > def change_view(self, request, object_id, form_url='', extra_context=None): > > """ self = SubstanceAdmin > request = wsgi request object > object_id = substance > form_url = no idea! > extra_context = dict of apps, models, admin_urls and permissions > > https://docs.djangoproject.com/en/1.11/ref/contrib/admin/#django. > contrib.admin.ModelAdmin.change_view > > """ > # Let the ModelAdmin resume normal operations with its own template > self.change_form_template = None > # queryset of m2m records from the 'through' table > ingredients = Substance_Ingredients.objects.filter(substance_id=object_id) > subscription = None > for sm2mi in ingredients: > # sm2mi.fee_payable() is the detector which triggers the process > payable, fee_type = sm2mi.fee_payable() # eg., True, PAID_DATA > if payable: > # generate a subscription record with blank token field or > # if one exists with a non-blank token, return None > subscription = billing_subscribe(sm2mi, fee_type) > if subscription: # collect money for the owner > # switch the ModelAdmin to the new template > self.change_form_template = 'payment.html' > # assemble all the necessary data for the view > context = billing_collect_context( > sm2mi, > subscription, > ) > # get everything into the payment_view context > if not extra_context: > extra_context = dict() > extra_context.update(self.admin_site.each_context(request)) > extra_context.update(context) > # wrap the view to protect it with Admin permissions > self.admin_site.admin_view( > # call the view with request and context > billing_payment_view( > request, > sm2mi, > subscription, > context=extra_context, > ) > ) > # only one sm2mi at a time > break > return super(SubstanceAdmin, self).change_view( > request, object_id, form_url, extra_context > ) > > > > > > 7. Call super in the model save() method *or* raise an exception to > prevent saving. I'm actually not sure about this bit. It may go against the > Django flow. However, I do use a BusinessRuleViolation exception which > inherits from ValidationError and therefore lets me include a human > readable message which appears in the Admin and *seems* to prevent saving. > You would need to test this especially with m2m side-effects and atomicity > consequences. > > I hope this helps. > > Mike > > > Considering the following model: > > > # Bloc fonctionnel > class Assembly(Item): > > product = models.ForeignKey(to='ProductFamily', on_delete=models. > CASCADE, null=True, verbose_name=_('Famille Produit')) > functions = models.ManyToManyField(Function, verbose_name=_( > 'Fonctions')) > *performances* = models.ManyToManyField(Performance, verbose_name=_( > 'Performances'), related_name='performances') > > def _get_type(self): > return ItemType.ASSEMBLY > > class Meta: > verbose_name = _('Bloc Fonctionnel') > verbose_name_plural = _('Blocs Fonctionnels') > > > > I have a custom AssemblyAdmin related to it and also a custom AssemblyForm > for customizing some fieds. > > The *performances* m2m field is critical. > The performances are captured in the form with a dynamic_raw_id field, > which works fine. > > But when this field is modified, some updates/deletions might be applied > in other tables of the database. > For this purpose, I need to collect the "performance" pk captured in the > html form and compare them with those currently in the database. > > Basically, when the user clicks on the regular "Save" or "Save and > continue" button, I would need to display an alert form (like when you > click on the delete button) to explain what would happen. > > I struggled with some ajax routines but it does not work as expected. > > I don't know if it's really doable and how to achieve it. > > Any suggestion is welcome. > > Cheers. > > Z. > > > > > > > > -- > You received this message because you are subscribed to the Google Groups > "Django users" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to [email protected] <javascript:>. > To post to this group, send email to [email protected] > <javascript:>. > Visit this group at https://groups.google.com/group/django-users. > To view this discussion on the web visit > https://groups.google.com/d/msgid/django-users/88135218-a965-46c8-a454-c0376a5682f1%40googlegroups.com > > <https://groups.google.com/d/msgid/django-users/88135218-a965-46c8-a454-c0376a5682f1%40googlegroups.com?utm_medium=email&utm_source=footer> > . > For more options, visit https://groups.google.com/d/optout. > > > -- You received this message because you are subscribed to the Google Groups "Django users" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To post to this group, send email to [email protected]. Visit this group at https://groups.google.com/group/django-users. To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/2482cf9f-5ee9-4ae8-9046-daca0d758e8e%40googlegroups.com. For more options, visit https://groups.google.com/d/optout.

