awesto / django-shop

A Django based shop system
http://www.django-shop.org
BSD 3-Clause "New" or "Revised" License
3.17k stars 1.04k forks source link

Reverse admin url of Customer Model #785

Open pydrogo opened 4 years ago

pydrogo commented 4 years ago

how can I get the reverse admin URL of the customer model? I tried: reverse('admin:shop_customer_changelist') but could not get it. could anyone help me, please?

jrief commented 4 years ago

It's admin:shop_customerproxy_changelist

Small hint to find out yourself:

>>> from django.urls import *
>>> resolve('/en/admin/shop/customerproxy/')
ResolverMatch(func=django.contrib.admin.options.changelist_view, args=(), kwargs={}, url_name=shop_customerproxy_changelist, app_names=['admin'], namespaces=['admin'])
>>> reverse('admin:shop_customerproxy_changelist')
'/en/admin/shop/customerproxy/'
pydrogo commented 4 years ago

I really appreciated your comprehensive answer. I could get the URL using your solution. I wanted to ask your idea about getting this URL dynamically using the Customer model. I have this in my admin.py:

@admin.register(AnswerSheetModel)
class AnswerSheetModelAdmin(admin.ModelAdmin):
    list_display = ('get_customer')

    @admin_link('customer', 'Customer')
    def get_customer(self, customer):
        return customer

and here is my decorator:

def admin_change_url(obj):
    app_label = obj._meta.app_label
    model_name = obj._meta.model.__name__.lower()
    return reverse('admin:{}_{}_change'.format(
        app_label, model_name
    ), args=(obj.pk,))

def admin_link(attr, short_description, empty_description="-"):
    def wrap(func):
        def field_func(self, obj):
            related_obj = getattr(obj, attr)
            if related_obj is None:
                return empty_description
            url = admin_change_url(related_obj)
            return format_html(
                '<a href="{}">{}</a>',
                url,
                func(self, related_obj)
            )
        field_func.short_description = short_description
        field_func.allow_tags = True
        return field_func
    return wrap

It gives the admin URL for change model page. Is adding an if statement for determining the Customer model only solution? like this:

def admin_change_url(obj):
    app_label = obj._meta.app_label
    model_name = obj._meta.model.__name__.lower()
    if model_name == 'customer':
        return reverse('admin:shop_customerproxy_change', args=(obj.pk,))
    return reverse('admin:{}_{}_change'.format(
        app_label, model_name
    ), args=(obj.pk,))

Is there any better solution?

jrief commented 4 years ago

What shall AnswerSheetModelAdmin do?

BTW, if you are using a tuple in list_display = ('get_customer'), don't forget the comma – you did. It is better to use lists anyway.

pydrogo commented 4 years ago

Here is my AnswerSheetModel:

class AnswerSheetModel(BaseModel):
    questionnaire = models.ForeignKey(QuestionnaireModel, on_delete=models.DO_NOTHING, related_name='answers')
    customer = models.ForeignKey(Customer, on_delete=models.DO_NOTHING, null=False, blank=False)
    ip = models.CharField(null=True, max_length=20)

    def __str__(self):
        return self.questionnaire.name + ': ' + self.customer.first_name + ' ' + self.customer.last_name

BTW, if you are using a tuple in list_display = ('get_customer'), don't forget the comma – you did.

thank you very much, yes I have trailing comma, I deleted it Here for simplicity :-)

jhonvidal commented 4 years ago

It's admin:shop_customerproxy_changelist

Small hint to find out yourself:

  • Go to the admin page you are looking for.
  • Copy the URL without the site part, here /en/admin/shop/customerproxy/.
  • Run ./manage.py shell
  • Use that URL in function resolve.
  • Recheck with reverse if the URL is the same.
>>> from django.urls import *
>>> resolve('/en/admin/shop/customerproxy/')
ResolverMatch(func=django.contrib.admin.options.changelist_view, args=(), kwargs={}, url_name=shop_customerproxy_changelist, app_names=['admin'], namespaces=['admin'])
>>> reverse('admin:shop_customerproxy_changelist')
'/en/admin/shop/customerproxy/'

Regarding that URL, I have problems accessing the following addresses:

http://localhost:8000/es/admin/shop/customerproxy/4/change/ or http://localhost:8000/es/admin/shop/customerproxy/add/

I have the following error:

TypeError at /es/admin/shop/customerproxy/4/change/

has_add_permission() takes 2 positional arguments but 3 were given

Request Method:     GET
Request URL:    http://localhost:8000/es/admin/shop/customerproxy/4/change/
Django Version:     3.0.7
Exception Type:     TypeError
Exception Value:    

has_add_permission() takes 2 positional arguments but 3 were given

Exception Location:     /home/ikki/.virtualenvs/vmedexample/lib/python3.6/site-packages/django/contrib/admin/options.py in get_inline_instances, line 596
Python Executable:  /home/ikki/.virtualenvs/vmedexample/bin/python
Python Version:     3.6.0
Python Path:    

['/home/ikki/Desarrollo/implementacion/medexample',
 '/home/ikki/Desarrollo/implementacion/medexample',
 '/home/ikki/Desarrollo/ide/pycharm-2020.1.1/plugins/python/helpers/pycharm_display',
 '/home/ikki/.pyenv/versions/3.6.0/lib/python36.zip',
 '/home/ikki/.pyenv/versions/3.6.0/lib/python3.6',
 '/home/ikki/.pyenv/versions/3.6.0/lib/python3.6/lib-dynload',
 '/home/ikki/.virtualenvs/vmedexample/lib/python3.6/site-packages',
 '/home/ikki/Desarrollo/ide/pycharm-2020.1.1/plugins/python/helpers/pycharm_matplotlib_backend']

Server time:    Lun, 15 Jun 2020 16:33:36 +0000

I have made from the installation cookiecutter-django-shop by default with all the sample data.

what is the solution?