On 20/06/2017 1:13 PM, Mike Dewhirst wrote:
On 20/06/2017 2:22 AM, 'Victor Hooi' via Django users wrote:
If you go down the user-profiles route - how would you handle managing each of those via the Django Admin?

I use group permissions to reveal or hide models in the Admin main menu. I use admin, editor, author and for example authors cannot see/edit company, addresses or phone numbers . And so on.


For example - say you have 3 user "types" - each just being User, with a different profile linked to it. How would you manage each of those via the admin interface?

I do a similar thing. Any substance can have one or two of a few physical_state(s). Different physical forms have different data to be collected. However, all of them have a subset of the same data. So I use a core_fields model with abstract = True and all the solid, liquid, gas etc models inherit from core fields. All the attributes and methods in cvommon live on the core_fields abstract model.

In the Admin I detect the substance physical_state and only present the appropriate models. One choice is solid and liquid. If that is selected the substance gets both "profiles"

For a new substance, all those I select one of the choices and save to make the unwanted profiles disappear. Provided no data was entered in the unwanted models, they never get created.

You need a bit of jiggery pokery in admin.py but it can be done. I'll try and get some time later to show you.

This is quite complex at first glance but very straightforward Python code living in the SubstanceAdmin class (at the end) in substance admin.py. The way I have arranged a substance is to have intrinsic properties and other information in related models/tables. So each of the inline classes below represents one of those related models. When registering those inlines for a new substance, all inlines are used because we don't yet know what physical state the substance will be.

The method below get_inline_instances() (https://docs.djangoproject.com/en/1.10/ref/contrib/admin/#django.contrib.admin.ModelAdmin.get_inline_instances) simply assembles the appropriate lists of inlines for the physical state of the substance. min_1_inlines and min_3_inlines are both always included at the top and tail of the list but others vary depending on physical state. And of course, the sequence in which they appear in the final list is important because that is how they appear on the page.

Finally, physical_state is an IntegerField and I use constants to represent SOLID, LIQUID etc. Here is the arrangement ...

SOLID = 1
LIQUID = 2
GAS = 4
AEROSOL = 8

... which lets me have any combinations like SOLID + LIQUID = 3 which are all unique in choices. See solid_liquid_inlines below.


    # excerpt from admin.py

    min_1_inlines = [
        LinkInline,
        PapersInline,
        SynonymsInline,
        UsesInline,
        IngredientsInline,
        GroupsInline,
    ]

    min_2_inlines = [
        ExplosiveInline,
        DesensitizedExpInline,
        OrganicPeroxideInline,
        SelfReactiveInline,
    ]

    min_3_inlines = [
        FirstaidInline,
        FireInline,
        SpillInline,
        EngineeringInline,
        LimitsInline,
        PpeInline,
        ExposureInline,
        HealthInline,
        OrganInline,
        AquaticInline,
        TerrestrialInline,
        DisposalInline,
        RegistryInline,
        NotesInline,
    ]

    solid_inlines = min_1_inlines + [
        SolidInline,
        ] + min_2_inlines + min_3_inlines

    liquid_inlines = min_1_inlines + [
        LiquidInline,
        ] + min_2_inlines + min_3_inlines

    solid_liquid_inlines = min_1_inlines + [
        SolidInline,
        LiquidInline,
        ] + min_2_inlines + min_3_inlines

    gas_inlines = min_1_inlines + [
        GasInline,
        ] + min_2_inlines + min_3_inlines

    aerosol_inlines = min_1_inlines + [
        AerosolInline,
        ] + min_3_inlines

    all_inlines = min_1_inlines + [
        SolidInline,
        LiquidInline,
        GasInline,
        AerosolInline,
        ] + min_2_inlines + min_3_inlines

    def get_inline_instances(
        self,
        request,
        obj=None,
        # now get each of the above inline lists into this scope
        all_inlines=all_inlines,
        aerosol_inlines=aerosol_inlines,
        gas_inlines=gas_inlines,
        liquid_inlines=liquid_inlines,
        solid_inlines=solid_inlines,
        solid_liquid_inlines=solid_liquid_inlines
        ):
        physical_state = 0
        if obj is not None and hasattr(obj, 'physical_state'):
            physical_state = obj.physical_state
        if physical_state == LIQUID:
return [inline(self.model, self.admin_site) for inline in liquid_inlines]
        elif physical_state == SOLID:
return [inline(self.model, self.admin_site) for inline in solid_inlines]
        elif physical_state == SOLID + LIQUID:
return [inline(self.model, self.admin_site) for inline in solid_liquid_inlines]
        elif physical_state == GAS:
return [inline(self.model, self.admin_site) for inline in gas_inlines]
        elif physical_state == AEROSOL:
return [inline(self.model, self.admin_site) for inline in aerosol_inlines] return [inline(self.model, self.admin_site) for inline in all_inlines]







On Mon, 19 Jun 2017 at 17:53 James Schneider <[email protected] <mailto:[email protected]>> wrote:



    On Jun 18, 2017 10:11 PM, "Victor Hooi" <[email protected]
    <mailto:[email protected]>> wrote:

        Hi,

        Say you have multiple custom users, each inheriting from
        AbstractUser. The docs mention setting AUTH_USER_MODEL:

https://docs.djangoproject.com/en/1.11/topics/auth/customizing/#substituting-a-custom-user-model

        However, what happens if you have *multiple* custom users -
        which would you set it to?


    The answer is to rethink your user model(s). The idea being that a
    'user' should be thought about at a very high level.

    There should only be one canon user model in use as far as system
    authentication is concerned. The 'type' of user rarely warrants
    the use of a separate model, rather the type would typically be
    made available as an attribute of your system User (notice the
    capital U), restricted by either a static list of possible choices
(https://docs.djangoproject.com/en/1.11/ref/models/fields/#choices)
    or by utilizing a foreign key to another model containing the list
    of potential user types.

    Your User model (which can be named anything you like, I'm just
    referencing User for brevity) should contain only a minimal amount
    of information needed for authentication, and any information that
    would be needed regularly on every request.

    Ideally, the User 'type' would be made a part of the User Profile,
    which can be recalled quickly via a 1to1 FK relationship
(https://docs.djangoproject.com/en/1.11/topics/auth/customizing/#extending-the-existing-user-model).

    One of the few cases where this information could be stored
    directly on the User is when the authorization system (permissions
    and user tests for access) are contingent on the 'type' of user
    you are examining, which effectively turns it into a role.
    However, unless you have a static (unchanging) list of user roles
    (which is a more apropos description anyway), you may still
    consider using a M2M relationship to a role table and update the
    User manager to automatically join the two tables when users are
    queried.

    Having separate 'user' models as you've mentioned leads to the
    exact issue you've brought up. If you are trying to find a user,
    you need a separate query for every type of user you have in every
    location where you need a list of users or perform searching for
    specific users. This causes an artificial and unnecessary
    inflation of the number of queries run for each request, and
    complicates the code trying to parse multiple sets of results.

    Proxy models may also be an alternative
(https://docs.djangoproject.com/en/1.11/topics/db/models/#proxy-models).
    However, those can be a bit unwieldy to handle and present the
    same issues as pulling a user list.

    -James




-- You received this message because you are subscribed to a topic in
    the Google Groups "Django users" group.
    To unsubscribe from this topic, visit
https://groups.google.com/d/topic/django-users/UrUN9PWKwMs/unsubscribe.
    To unsubscribe from this group and all its topics, send an email
    to [email protected]
    <mailto:[email protected]>.
    To post to this group, send email to [email protected]
    <mailto:[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/CA%2Be%2BciWkc8XrQEnS9ET12Y%3D5nToFV29QTqHwOrcPMX_rvEM17g%40mail.gmail.com
<https://groups.google.com/d/msgid/django-users/CA%2Be%2BciWkc8XrQEnS9ET12Y%3D5nToFV29QTqHwOrcPMX_rvEM17g%40mail.gmail.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] <mailto:[email protected]>. To post to this group, send email to [email protected] <mailto:[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/CAMnnoUK%3Db848dQjCSUvUv45-2P8sZx1tRj-%3D0%2BzMeNA7sCiKSw%40mail.gmail.com <https://groups.google.com/d/msgid/django-users/CAMnnoUK%3Db848dQjCSUvUv45-2P8sZx1tRj-%3D0%2BzMeNA7sCiKSw%40mail.gmail.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/d3a1418a-f57a-0918-2b0f-c866a42e27e3%40dewhirst.com.au.
For more options, visit https://groups.google.com/d/optout.

Reply via email to