Admin site and ModelAdmin

33 views
Skip to first unread message

jt.ol...@gmail.com

unread,
May 2, 2018, 5:13:29 PM5/2/18
to Django users
I'm new to Django and web development in general (C++ background) and I've got amazingly far very quickly, but there's one thing I've been struggling with for a couple days now :-(. Forgive me if I screw up the lingo.

I've got a ModelAdmin page for registrants of a conference which has fields for Employee ID, Name, email etc. The registrant does not have to be an employee, but if they are I could lookup their name, email etc. from an external source (already have the Python code for this). I'd like to have a button next to the employee id field which would lookup the employee's details and fill in the appropriate fields. This seems to me that it shouldn't be too hard but I am spinning my wheels here.  Do I need to ditch ModelAdmin?  Can someone please point me in the right direction.

Thanks,
JT

Mike Dewhirst

unread,
May 2, 2018, 8:34:05 PM5/2/18
to django...@googlegroups.com
You may not need a button which, in the Admin, implies javascript and an
API. In your model you can intercept the save() method to visit another
database/system to fetch the detail before the record is saved. There
are probably many ways to do this. One uses a pre-save signal [1] but I
prefer to override save() [2].

class Employee(models.Model):

    ... all the fields etc

    fetchdata = models.BooleanField(default=False, blank=True)

    def save(self, *args, **kwargs):
        if self.fetchdata:
            self.fetchdata = False
            try:
                self.this, self.that = self.fetch_data()
            except Exception:
                # avoid losing other changes
                pass
        super(Substance, self).save(*args, **kwargs)

    def fetch_data(self):
        #call external database with employee ID and return necessary
detail
        return this, that

[1] https://docs.djangoproject.com/en/1.11/ref/signals/#pre-save
[2]
https://docs.djangoproject.com/en/2.0/ref/models/instances/#saving-objects

hth

>
> Thanks,
> JT
> --
> 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 django-users...@googlegroups.com
> <mailto:django-users...@googlegroups.com>.
> To post to this group, send email to django...@googlegroups.com
> <mailto:django...@googlegroups.com>.
> 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/1324e38c-ed15-4f3c-8e1e-cd7df220b96e%40googlegroups.com
> <https://groups.google.com/d/msgid/django-users/1324e38c-ed15-4f3c-8e1e-cd7df220b96e%40googlegroups.com?utm_medium=email&utm_source=footer>.
> For more options, visit https://groups.google.com/d/optout.

Mike Dewhirst

unread,
May 2, 2018, 8:37:33 PM5/2/18
to django...@googlegroups.com
             super(Employee, self).save(*args, **kwargs)

Sorry - should have read what I pasted in

jt.ol...@gmail.com

unread,
May 3, 2018, 5:02:09 PM5/3/18
to Django users
Thanks for the response Mike.

I generally don't like it when a design has to change to fit a framework, however, in this case I decided to try your solution. I ran into a couple of problems though :-(
 1) The fields that I'm looking up were required fields. Validation failed and error messages were displayed until I changed my model to not require those fields (which creates other problems I'd need to fix). Is there a way to hook in before validation? I over-road the model save function. Would the pre-save signal method fix this problem? Or maybe ModelAdmin.save_model?
 2) The desired result of the lookup would be to display the change form so that the information could be verified. In other words, if doing the lookup, 'SAVE' (and 'Save and add another') should behave as if 'Save and continue editing' had been selected.


Mike Dewhirst

unread,
May 4, 2018, 2:23:08 AM5/4/18
to django...@googlegroups.com
On 4/05/2018 7:02 AM, jt.ol...@gmail.com wrote:
> Thanks for the response Mike.
>
> I generally don't like it when a design has to change to fit a framework,

I agree. My design is almost entirely in the models. I want an API to be
able to work without Django forms.

> however, in this case I decided to try your solution. I ran into a
> couple of problems though :-(
>  1) The fields that I'm looking up were required fields. Validation
> failed and error messages were displayed until I changed my model to
> not require those fields (which creates other problems I'd need to
> fix). Is there a way to hook in before validation?

Maybe but not in the model. I think you should be able to intercept form
validation. But see below.

> I over-road the model save function. Would the pre-save signal method
> fix this problem?
No
> Or maybe ModelAdmin.save_model?
Don't know. Possibly.

Django forms automatically do all the python-wise cleaning of data prior
to the model's save() being called by the form If you are putting data
independently from the form into fields inside the save() method (or via
a pre_save hook) you have to be certain it is valid data.

I might be wrong but I don't think there is any effective difference
between pre and post save signals and my approach. Maybe transaction
management. Maybe not. This is my exact substance.save() method ...

    def save(self, *args, **kwargs):
        links = self._pre_save()
        super(Substance, self).save(*args, **kwargs)
        self._post_save(links)
        self._post_post_save()

Stuff which occurs in _pre_save() happens before the record is saved to
the database. For example, the record may not yet have a primary key
because it is new and hasn't ever been saved to the database. Stuff in
_post_save() and _post_post_save() happens afterwards. I use those to
create related records if required because by then (under normal circs)
I can guarantee self.id is no longer null.

The last thing which happens prior to save() is the model's clean()
method (if it exists) is called by the form. I put checks in there to be
certain data in whatever fields I care deeply about is valid and raise a
ValidationError if not. If that happens, the save() is aborted and the
user has to fix the problem before trying again. Here is an example ...

    def clean(self):
        if self.physical_state is None:
            raise ValidationError('Physical form is required')

If you are getting external data you have no choice but to be certain it
is good data. You need to validate it Python-wise en route to the
destination model fields, perhaps in _pre_save() and business-rule-wise
in Employee.clean()

The actual validation checks can be factored out and called from clean()
or anywhere else such as save().

The actual sequence of events (form calls model.clean() before
model.save()) indicates to me that Employee.clean() ought to be able to
insert (clean) data into Employee fields before running its own business
rule validation. However, whenever I have tried this I haven't been
successful. Therefore I'm missing something. Maybe transaction
management. Maybe someone can enlighten me?

A side note is that if you are not using a form, clean() does not get
called. This matters for unit testing where there is no form. You have
to deliberately call clean() to get the benefit of any checks.

>  2) The desired result of the lookup would be to display the change
> form so that the information could be verified.

Sorry but that implies javascript and an API to fetch the data for
verification if you want to do it all at once.

OTOH maybe you could save the Employee model without the external data
and use a separate 1:1 model to carry it. That could be fetched
separately after the Emplyee.save() has run. In my scenario it would be
fetched in the _post_save() method and verified python-wise in there
before adding the 1:1 model if it didn't already exist. The Employee
would need to be saved again so the 1:1 model gets saved. The 1:1 model
could check the business rule logic in its clean() method. Maybe the
advantage here would be splitting the activity into separate atomic
transactions and a 1:1 model validation error wouldn't interrupt the
preceding Employee.save()

> In other words, if doing the lookup, 'SAVE' (and 'Save and add
> another') should behave as if 'Save and continue editing' had been
> selected.

There is no save/clean difference between any of those. Just what
happens next in the Admin.

>
>
> --
> 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 django-users...@googlegroups.com
> <mailto:django-users...@googlegroups.com>.
> To post to this group, send email to django...@googlegroups.com
> <mailto:django...@googlegroups.com>.
> 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/26f88b4c-b2dd-4bce-aea7-d885295aa609%40googlegroups.com
> <https://groups.google.com/d/msgid/django-users/26f88b4c-b2dd-4bce-aea7-d885295aa609%40googlegroups.com?utm_medium=email&utm_source=footer>.
Reply all
Reply to author
Forward
0 new messages