简体   繁体   中英

Does django's URL Conf support mapping an argument to strings?

The Problem

I'm unsure of the best way to phrase this, but here goes: (note some of this may not be syntactically/semantically correct, as it's not my actual code, but I needed it to help explain what I'm asking)

Say I have a model the model Album :

Class Album(models.Model):
    ALBUM_TYPE_SINGLE = 1
    ALBUM_TYPE_DEMO = 2
    ALBUM_TYPE_GREATEST_HITS = 3
    ALBUM_CHOICES = (
        (ALBUM_TYPE_SINGLE, 'Single Record'),
        (ALBUM_TYPE_DEMO, 'Demo Album'),
        (ALBUM_TYPE_GREATEST_HITS, 'Greatest Hits'),
    )
    album_type = models.IntegerField(choices=ALBUM_CHOICES)

And I want to have separate URLs for the various types of albums. Currently, the URL Conf is something like so:

urlpatterns = [
    url(r'^singles/(?P<pk>.+)/$', views.AlbumView, name="singles"),
    url(r'^demos/(?P<pk>.+)/$', views.AlbumView, name="demos"),
    url(r'^greatest-hits/(?P<pk>.+)/$', views.AlbumView, name="greatest_hits"),
]

And when I want to serve the appropriate URL, I need to check the album_type manually:

if object.album_type == Album.ALBUM_TYPE_SINGLE:
    return reverse('singles', object.id)
elif object.album_type == Album.ALBUM_TYPE_DEMO:
    return reverse('demos', object.id)
elif object.album_type == Album.ALBUM_TYPE_GREATEST_HITS:
    return reverse('greatest_hits', object.id)

However, this is cumbersome to do, and I'm wondering if there is a way to pass in the album_type field to the call to reverse and have it automatically get the URL based on that. ie something like this:

urlpatterns = [
    url(r'^(?P<type>[singles|demos|greatest-hits])/(?P<pk>.+)/$', views.AlbumView, name="albums"),
]

and called with

reverse("albums", object.album_type, object.id)

Attempted solutions

I considered setting the choice strings to be

ALBUM_CHOICES = (
    (ALBUM_TYPE_SINGLE, 'singles'),
    (ALBUM_TYPE_DEMO, 'demos'),
    (ALBUM_TYPE_GREATEST_HITS, 'greatest-hits'),
)

which would then allow me to send object.get_album_type_display() as a string variable for type, which works, however, I need to be able to use reverse to build the URL while only having access to the integer value of album_type and not the display value.

I know this is an oddly specific question for an oddly specific scenario, but if anyone has any kind of potential solutions, I'd be very grateful! Thank you in advance!

I would change the field to a CharField , and use the URL slug as the actual value rather than the display value:

Class Album(models.Model):
    ALBUM_TYPE_SINGLE = 'singles'
    ALBUM_TYPE_DEMO = 'demos'
    ALBUM_TYPE_GREATEST_HITS = 'greatest-hits'
    ALBUM_CHOICES = (
        (ALBUM_TYPE_SINGLE, 'Single Record'),
        (ALBUM_TYPE_DEMO, 'Demo Album'),
        (ALBUM_TYPE_GREATEST_HITS, 'Greatest Hits'),
    )
    album_type = models.CharField(choices=ALBUM_CHOICES, max_length=50)

In your urls.py :

urlpatterns = [
    url(r'^(?P<type>singles|demos|greatest-hits)/(?P<pk>.+)/$', views.AlbumView, name="albums"),
]

Then you can reverse it by passing album.album_type :

reverse('albums', args=(album.album_type, album.pk))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM