Django:{% url } 标签中的 UUID 类型

kar*_*lok 4 django django-urls datastax-enterprise datastax-startup

介绍

我正在关注Django 教程。相比之下,我有两个数据库——MySql 和 Cassandra。因此,我还需要使用包含UUID类型的 Cassandra 模型。UUID 的形式为 32 个字母数字字符和四个连字符 (8-4-4-12)。因此,我的 urls.py 中有相当复杂的正则表达式:

^([A-Fa-f0-9]{8}))(-[A-Fa-f0-9]{4}){3}-[A-Fa-f0-9]{12}
Run Code Online (Sandbox Code Playgroud)

问题

polls/templates/polls/detail.htmlteplate 中是以下行:

<form action="{% url 'polls:vote' question.question_id %}" method="post">
Run Code Online (Sandbox Code Playgroud)

然后将 UUID 类型question.question_id转换为:

/polls/UUID('47de663a-57f2-4ca1-9ad9-81df9ae25973')/

代替

/polls/47de663a-57f2-4ca1-9ad9-81df9ae25973/

因此,我收到了错误消息:

使用参数 '(UUID('47de663a-57f2-4ca1-9ad9-81df9ae25973'),)' 和关键字参数 '{}' 未找到反向'投票'。尝试了 1 个模式:[u'polls/(?P^([A-Fa-f0-9]{8})(-[A-Fa-f0-9]{4}){3}-[ A-Fa-f0-9]{12})/vote/$'

如何处理 UUID 类型?

我想我不能在{% url}标签中使用 str(question.question_id) 函数。

来源

根网址 - mysite/urls.py:

from django.conf.urls import url

from . import views

app_name= 'polls'
urlpatterns = [
    #ex: /polls/
    url(r'^$',views.index, name='index'),
    #ex: /polls/uuid
    url(r'^(?P<question_id>^([A-Fa-f0-9]{8})(-[A-Fa-f0-9]{4}){3}-[A-Fa-f0-9]{12})/$', views.detail, name='detail'),
    #ex: /polls/uuid/results/
    url(r'^(?P<question_id>^([A-Fa-f0-9]{8})(-[A-Fa-f0-9]{4}){3}-[A-Fa-f0-9]{12})/results/$', views.results, name='results'),
    #ex: /polls/uuid/vote
    url(r'^(?P<question_id>^([A-Fa-f0-9]{8})(-[A-Fa-f0-9]{4}){3}-[A-Fa-f0-9]{12})/vote/$', views.vote, name='vote'),
]
Run Code Online (Sandbox Code Playgroud)

民意调查应用程序 polls/urls.py:

from django.conf.urls import url
from . import views

app_name= 'polls'
urlpatterns = [
    url(r'^$',views.index, name='index'),
    #ex: polls/5/results/
    url(r'^(?P<question_id>[0-9]+)/results/$', views.results, name='results'),
    #ex: /polls/5/volte
    url(r'^(?P<question_id>(^([A-Fa-f0-9]{8}))(-[A-Fa-f0-9]{4}){3}-[A-Fa-f0-9]{12})/vote/$', views.vote, name='vote'),
    #ex: polls/5/
    url(r'^(?P<question_id>[^/]+)/$',views.detail, name='detail'),
]
Run Code Online (Sandbox Code Playgroud)

民意调查/views.py:

from django.shortcuts import render

# Create your views here.

from django.shortcuts import render, get_object_or_404
from .models import Question, Choice
from django.shortcuts import get_object_or_404, render


def index(request):
   #latest_question_list = Question.objects.order_by('-pub_date')[5:]
   latest_question_list = Question.objects()
   context = {
       'latest_question_list': latest_question_list,
   }
   return render(request, 'polls/index.html', context)


def detail(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    return render(request, 'polls/detail.html', {'question':question})


def vote(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    try:
        selected_choice = get_object_or_404(Choice, pk=question_id)
        #selected_choice = question.choice_set.get(pk=request.POST['choice'])
    except (KeyError, Choice.DoesNotExist):
        # Redisplay the question voting form.
        return render(request, 'polls/detail.html', {
            'question': question,
            'error_message': "You didn't select a choice.",
        })
    else:
        selected_choice.votes += 1
        selected_choice.save()
        # Always return an HttpResponseRedirect after successfully dealing
        # with POST data. This prevents data from being posted twice if a
        # user hits the Back button.
        return HttpResponseRedirect(
            reverse('polls:results', args=(question.question_id,))
        )

def results(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    return render(request, 'polls/results.html', {'question': question})
Run Code Online (Sandbox Code Playgroud)

民意调查/模板/民意调查/detail.html:

<h1>{{ question.question_text }}</h1>

{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}

<form action="{% url 'polls:vote' question.question_id %}" method="post">
    {% csrf_token %}
    {% for choice in question.choice_set.all %}
        <input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}" />
        <label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br />
    {% endfor %}
    <input type="submit" value="Vote" />
</form>  
Run Code Online (Sandbox Code Playgroud)

民意调查/模型.py:

from django.db import models

# Create your models here

import uuid
from cassandra.cqlengine import columns
from cassandra.cqlengine import models


from django_cassandra_engine.models import DjangoCassandraModel

class User(models.Model):
    username = columns.Text(primary_key=True)
    password = columns.Text()
    email = columns.Text()
    fullname = columns.Text()
    is_staff = columns.Boolean(default=False)

class ExampleModel(DjangoCassandraModel):
    example_id    = columns.UUID(primary_key=True, default=uuid.uuid4)
    example_type  = columns.Integer(index=True)
    created_at    = columns.DateTime()
    description   = columns.Text(required=False)

class Question(DjangoCassandraModel):
    def __str__(self):
        return self.question_text
    question_id = columns.UUID(primary_key=True)
    question_text = columns.Text()
    pub_date = columns.TimeUUID()

class Choice(DjangoCassandraModel):
    def __str__(self):
        return self.choise_text
    question =  columns.UUID(primary_key=True)
    choice_text = columns.Text()
    votes = columns.Integer(index=True,default=0)
Run Code Online (Sandbox Code Playgroud)

Esc*_*her 6

你的question_id正则表达式是错误的。如果您uuid4按看起来的样子使用(并假设您不希望大写字母进行验证,因为 Pythonuuid.uuid4()在呈现为字符串时会生成小写字母),则question_id捕获组的正则表达式为:

(?P<question_id>[a-f0-9]{8}-?[a-f0-9]{4}-?4[a-f0-9]{3}-?[89ab][a-f0-9]{3}-?[a-f0-9]{12})
Run Code Online (Sandbox Code Playgroud)

为 Django 2.0 进行编辑:Django 现在具有路径转换器,因此您不再需要 uuid4 正则表达式。下面是一个例子:

from django.urls import path

urlpatterns = [
    path('questions/<uuid:question_id>/', MyView.as_view()), 
]
Run Code Online (Sandbox Code Playgroud)