在基于类的视图中使用多个 URL 参数来获取对象

Posted

技术标签:

【中文标题】在基于类的视图中使用多个 URL 参数来获取对象【英文标题】:Using Multiple URL Parameters to get_object in Class-Based-View 【发布时间】:2017-05-13 07:33:27 【问题描述】:

好的,我对此很陌生,我已经在我的项目上工作了几个月,我想创建接受多个参数来调用视图的 URL。示例 URL 如下所示: http://www.sample.com/builders//m//

通过在我的 DetailView 中覆盖 get_object,我已经成功实现了这一点,但我想知道是否有更好/更简单的方法来实现这一点,或者这是否被认为是一种不好的做法。任何指导将不胜感激。

urls.py

urlpatterns = [
    # url(r'^$', builder_list, name='list'),
    # url(r'^create/$', builder_create, name='create'),
    # url(r'^(?P<slug>[\w-]+)/$', builder_detail, name='detail'),
    # url(r'^(?P<slug>[\w-]+)/edit/$', builder_update, name='update'),
    # url(r'^(?P<slug>[\w-]+)/delete/$', builder_delete, name='delete'),

    # url(r'^$', builder_list, name='sub_list'),
    # url(r'^m/create/$', sub_create, name='sub_create'),
    url(r'^(?P<builder>[\w-]+)/m/(?P<market>[\w-]+)/$', sub_detail, name='sub_detail'),
    # url(r'^m/(?P<slug>[\w-]+)/edit/$', sub_update, name='sub_update'),
    # url(r'^m/(?P<slug>[\w-]+)/delete/$', sub_delete, name='sub_delete'),
]

views.py

class BuilderSubDetailView(DetailView):
    model = BuilderSub
    template_name = "builders/sub_detail.html"

    def get_context_data(self, **kwargs):
        context = super(BuilderSubDetailView, self).get_context_data(**kwargs)
        context['now'] = timezone.now()
        print(context)

        return context

    def get_object(self, queryset=None):
        if queryset is None:
            queryset = self.get_queryset()

        # Next, try looking up by primary key.
        builder = self.kwargs['builder']
        builder_id = Builder.objects.filter(slug=builder).first().pk
        market = self.kwargs['market']
        market_id = Market.objects.filter(slug=market).first().pk
        if builder is not None and market is not None:
            queryset = BuilderSub.objects.filter(parent=builder_id).filter(market=market_id)

        # If none of those are defined, it's an error.
        if builder is None or market is None:
            raise AttributeError("Generic detail view %s must be called with "
                                 "Builder and Market"
                                 % self.__class__.__name__)
        try:
            # Get the single item from the filtered queryset
            obj = queryset.get()
        except queryset.model.DoesNotExist:
            raise Http404("No %(verbose_name)s found matching the query") % \
                'verbose_name': queryset.model._meta.verbose_name
        return obj

还有 models.py 供参考——我的 get_absolute_url 函数也有问题吗?

class Builder(models.Model):
    added_by = models.ForeignKey(settings.AUTH_USER_MODEL, default=1)
    company_name = models.CharField(max_length=80, help_text="Full Company Name", unique=True)
    short_name = models.CharField(help_text="Short Company Name", max_length=30)
    slug = models.SlugField(unique=True)
    website = models.CharField(max_length=80, help_text="Format: www.[website].com")
    logo = models.ImageField(blank=True, null=True)
    timestamp = models.DateTimeField(auto_now_add=True)
    info = RedactorField(verbose_name=u'Company Info')

    def show_website_url(self):
        return format_html("<a href='url'>url</a>", url=self.website)

    def __str__(self):
        return self.short_name


class BuilderSub(models.Model):
    parent = models.ForeignKey(Builder)
    market = models.ForeignKey(Market, null=True, blank=True)
    details = RedactorField(verbose_name=u'Details', blank=True, null=True)
    main_contact = models.ForeignKey(Person, blank=True, null=True)

    def __str__(self):
        return ":  - ".format(self.pk, self.market.name, self.parent.short_name)

    def get_absolute_url(self):
        return reverse('builders:sub_detail', kwargs='market': self.market.slug, 'builder': self.parent.slug)


def pre_save_builder_reciever(sender, instance, *args, **kwargs):
    instance.slug = slugify(instance.short_name)

pre_save.connect(pre_save_builder_reciever, sender=Builder)

我不能 100% 确定我的 BuilderSub 模型是否适合处理整个 Builder(公司)与其所服务的市场之间的关系,因此我们也将不胜感激任何指导。

【问题讨论】:

我相信你可以创建多个具有不同参数的 url,然后将它们全部指向同一个视图。 【参考方案1】:

是的,确实有一种更合乎道德的方式来做到这一点。 DetailView 仅用于处理一个对象。然而,ListView 可以完成工作!

我已将 builder 和 market 替换为 city 和 category。

我也是初学者。希望我已经回答了你的问题:)

views.py

class EntryListView(generic.ListView):

template_name = 'myapp/category.html'
context_object_name = 'entry'
def get_queryset(self):
    city_id = self.kwargs['city']
    category_id = self.kwargs['category']
    entry = Entry.objects.all().filter(city=city_id).filter(category=category_id)
    return entry

urls.py

    url(r'^(?P<city>[0-9]+)/(?P<category>[0-9]+)/$', views.EntryListView.as_view(), name='entry'),

category.html

% extends 'myapp/base.html' %

% block body %

<table>
% for new in entry %
    <tr>
        <td>
            <img src = "new.image_url">
        <br>
            <b>Name :</b> new.name<br>
            % if new.phone %
            <B>Phone No. :</B> new.phone<br>
            % endif %
            <b>Address :</b> new.address<br>
        </td>
    </tr>
% endfor %

% endblock %

models.py

class Entry(models.Model):
    city = models.ForeignKey(City, on_delete=models.CASCADE)
    category = models.ForeignKey(Category, on_delete=models.CASCADE)
    name = models.CharField(max_length=250)
    phone = models.IntegerField(null=True)
    address =  models.CharField(max_length=250)
    image_url = models.CharField(max_length=500)
    def __str__(self):
        return self.name

【讨论】:

以上是关于在基于类的视图中使用多个 URL 参数来获取对象的主要内容,如果未能解决你的问题,请参考以下文章

基于类的视图中的可选 url 参数

如何使基于类的视图接受来自 URL 的参数或在 URLconf 中硬编码

带有参数的 Django 反向 url 到基于类的视图

django url如何使用问号? (基于类的视图)

在基于 Django 类的视图中使用 modelformset_factory

基于 URL 参数的多个视图文件夹