标签归档:django-views

在django-rest-framework中禁用ViewSet中的方法

问题:在django-rest-framework中禁用ViewSet中的方法

ViewSets 具有自动列出,检索,创建,更新,删除,…的方法

我想禁用其中一些,我想出的解决方案可能不是一个好方法,因为OPTIONS仍然指出了允许的范围。

关于如何正确执行此操作的任何想法吗?

class SampleViewSet(viewsets.ModelViewSet):
    queryset = api_models.Sample.objects.all()
    serializer_class = api_serializers.SampleSerializer

    def list(self, request):
        return Response(status=status.HTTP_405_METHOD_NOT_ALLOWED)
    def create(self, request):
        return Response(status=status.HTTP_405_METHOD_NOT_ALLOWED)

ViewSets have automatic methods to list, retrieve, create, update, delete, …

I would like to disable some of those, and the solution I came up with is probably not a good one, since OPTIONS still states those as allowed.

Any idea on how to do this the right way?

class SampleViewSet(viewsets.ModelViewSet):
    queryset = api_models.Sample.objects.all()
    serializer_class = api_serializers.SampleSerializer

    def list(self, request):
        return Response(status=status.HTTP_405_METHOD_NOT_ALLOWED)
    def create(self, request):
        return Response(status=status.HTTP_405_METHOD_NOT_ALLOWED)

回答 0

的定义ModelViewSet是:

class ModelViewSet(mixins.CreateModelMixin, 
                   mixins.RetrieveModelMixin, 
                   mixins.UpdateModelMixin,
                   mixins.DestroyModelMixin,
                   mixins.ListModelMixin,
                   GenericViewSet)

因此,除了扩展之外ModelViewSet,为什么不随便使用您需要的东西呢?因此,例如:

from rest_framework import viewsets, mixins

class SampleViewSet(mixins.RetrieveModelMixin,
                    mixins.UpdateModelMixin,
                    mixins.DestroyModelMixin,
                    viewsets.GenericViewSet):
    ...

使用这种方法,路由器应该只为所包含的方法生成路由。

参考

模型视图集

The definition of ModelViewSet is:

class ModelViewSet(mixins.CreateModelMixin, 
                   mixins.RetrieveModelMixin, 
                   mixins.UpdateModelMixin,
                   mixins.DestroyModelMixin,
                   mixins.ListModelMixin,
                   GenericViewSet)

So rather than extending ModelViewSet, why not just use whatever you need? So for example:

from rest_framework import viewsets, mixins

class SampleViewSet(mixins.RetrieveModelMixin,
                    mixins.UpdateModelMixin,
                    mixins.DestroyModelMixin,
                    viewsets.GenericViewSet):
    ...

With this approach, the router should only generate routes for the included methods.

Reference:

ModelViewSet


回答 1

您可以继续使用viewsets.ModelViewSethttp_method_names在ViewSet上进行定义。

class SampleViewSet(viewsets.ModelViewSet):
    queryset = api_models.Sample.objects.all()
    serializer_class = api_serializers.SampleSerializer
    http_method_names = ['get', 'post', 'head']

一旦你加入http_method_names,你将无法做到putpatch了。

如果您想要put但不想要patch,您可以保留http_method_names = ['get', 'post', 'head', 'put']

在内部,DRF视图从Django CBV扩展。Django CBV具有一个名为http_method_names的属性。因此,您也可以在DRF视图中使用http_method_names。

[Shameless Plug]:如果此答案有用,您将喜欢我在DRF上的系列文章,网址https://www.agiliq.com/blog/2019/04/drf-polls/

You could keep using viewsets.ModelViewSet and define http_method_names on your ViewSet.

Example

class SampleViewSet(viewsets.ModelViewSet):
    queryset = api_models.Sample.objects.all()
    serializer_class = api_serializers.SampleSerializer
    http_method_names = ['get', 'post', 'head']

Once you add http_method_names, you will not be able to do put and patch anymore.

If you want put but don’t want patch, you can keep http_method_names = ['get', 'post', 'head', 'put']

Internally, DRF Views extend from Django CBV. Django CBV has an attribute called http_method_names. So you can use http_method_names with DRF views too.

[Shameless Plug]: If this answer was helpful, you will like my series of posts on DRF at https://www.agiliq.com/blog/2019/04/drf-polls/.


回答 2

尽管这篇文章已经有一段时间了,但我突然发现实际上它们是禁用这些功能的一种方法,您可以直接在views.py中对其进行编辑。

资料来源:https : //www.django-rest-framework.org/api-guide/viewsets/#viewset-actions

from rest_framework import viewsets, status
from rest_framework.response import Response

class NameWhateverYouWantViewSet(viewsets.ModelViewSet):

    def create(self, request):
        response = {'message': 'Create function is not offered in this path.'}
        return Response(response, status=status.HTTP_403_FORBIDDEN)

    def update(self, request, pk=None):
        response = {'message': 'Update function is not offered in this path.'}
        return Response(response, status=status.HTTP_403_FORBIDDEN)

    def partial_update(self, request, pk=None):
        response = {'message': 'Update function is not offered in this path.'}
        return Response(response, status=status.HTTP_403_FORBIDDEN)

    def destroy(self, request, pk=None):
        response = {'message': 'Delete function is not offered in this path.'}
        return Response(response, status=status.HTTP_403_FORBIDDEN)

Although it’s been a while for this post, I suddenly found out that actually there is a way to disable those functions, you can edit it in the views.py directly.

Source: https://www.django-rest-framework.org/api-guide/viewsets/#viewset-actions

from rest_framework import viewsets, status
from rest_framework.response import Response

class NameThisClassWhateverYouWantViewSet(viewsets.ModelViewSet):

    def create(self, request):
        response = {'message': 'Create function is not offered in this path.'}
        return Response(response, status=status.HTTP_403_FORBIDDEN)

    def update(self, request, pk=None):
        response = {'message': 'Update function is not offered in this path.'}
        return Response(response, status=status.HTTP_403_FORBIDDEN)

    def partial_update(self, request, pk=None):
        response = {'message': 'Update function is not offered in this path.'}
        return Response(response, status=status.HTTP_403_FORBIDDEN)

    def destroy(self, request, pk=None):
        response = {'message': 'Delete function is not offered in this path.'}
        return Response(response, status=status.HTTP_403_FORBIDDEN)

回答 3

如果尝试从DRF视图集中禁用PUT方法,则可以创建一个自定义路由器:

from rest_framework.routers import DefaultRouter

class NoPutRouter(DefaultRouter):
    """
    Router class that disables the PUT method.
    """
    def get_method_map(self, viewset, method_map):

        bound_methods = super().get_method_map(viewset, method_map)

        if 'put' in bound_methods.keys():
            del bound_methods['put']

        return bound_methods

通过在路由器上禁用该方法,您的api模式文档将是正确的。

If you are trying to disable the PUT method from a DRF viewset, you can create a custom router:

from rest_framework.routers import DefaultRouter

class NoPutRouter(DefaultRouter):
    """
    Router class that disables the PUT method.
    """
    def get_method_map(self, viewset, method_map):

        bound_methods = super().get_method_map(viewset, method_map)

        if 'put' in bound_methods.keys():
            del bound_methods['put']

        return bound_methods

By disabling the method at the router, your api schema documentation will be correct.


回答 4

如何在DRF中为ViewSet禁用“删除”方法

class YourViewSet(viewsets.ModelViewSet):
    def _allowed_methods(self):
        return [m for m in super(YourViewSet, self)._allowed_methods() if m not in ['DELETE']]

PS这比显式指定所有必需的方法更可靠,因此很少有机会忘记一些重要的方法OPTIONS,HEAD等

默认情况下,DPS的PPS具有 http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']

How to disable “DELETE” method for ViewSet in DRF

class YourViewSet(viewsets.ModelViewSet):
    def _allowed_methods(self):
        return [m for m in super(YourViewSet, self)._allowed_methods() if m not in ['DELETE']]

P.S. This is more reliable than explicitly specifying all the necessary methods, so there is less chance of forgetting some of important methods OPTIONS, HEAD, etc

P.P.S. by default DRF has http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']


回答 5

在Django Rest Framework 3.xx中,您可以ModelViewSet通过将字典传递给as_view方法来简单地启用要启用的每个方法。在此字典中,键必须包含请求类型(GET,POST,DELETE等),并且值必须包含相应的方法名称(列表,检索,更新等)。例如,假设您要Sample创建或读取模型,但不希望对其进行修改。因此,这意味着你想listretrievecreate方法,是使(和你希望别人被禁用。)

您需要做的就是添加如下路径urlpatterns

path('sample/', SampleViewSet.as_view({
    'get': 'list',
    'post': 'create'
})),
path('sample/<pk>/', SampleViewSet.as_view({  # for get sample by id.
    'get': 'retrieve'
}))

如您所见,上述路由设置中没有no deleteputrequest,因此例如,如果您将put请求发送到url,它将以405响应您Method Not Allowed

{
    "detail": "Method \"PUT\" not allowed."
}

In Django Rest Framework 3.x.x you can simply enable every each method you want to be enabled for ModelViewSet, by passing a dictionary to as_view method. In this dictionary, the key must contain request type (GET, POST, DELETE, etc) and the value must contain corresponding method name (list, retrieve, update, etc). For example let say you want Sample model to be created or read but you don’t want it to be modified. So it means you want list, retrieve and create method to be enable (and you want others to be disabled.)

All you need to do is to add paths to urlpatterns like these:

path('sample/', SampleViewSet.as_view({
    'get': 'list',
    'post': 'create'
})),
path('sample/<pk>/', SampleViewSet.as_view({  # for get sample by id.
    'get': 'retrieve'
}))

As you can see there’s no delete and put request in above routing settings, so for example if you send a put request to the url, it response you with 405 Method Not Allowed:

{
    "detail": "Method \"PUT\" not allowed."
}

回答 6

如果您打算禁用放置/发布/销毁方法,则可以使用

viewsets.ReadOnlyModelViewSet https://www.django-rest-framework.org/tutorial/6-viewsets-and-routers/#refactoring-to-use-viewsets

If you are planning to disable put/post/destroy methods, you can use

viewsets.ReadOnlyModelViewSet https://www.django-rest-framework.org/tutorial/6-viewsets-and-routers/#refactoring-to-use-viewsets


Django基于类的视图:如何将其他参数传递给as_view方法?

问题:Django基于类的视图:如何将其他参数传递给as_view方法?

我有一个基于类的自定义视图

# myapp/views.py
from django.views.generic import *

class MyView(DetailView):
    template_name = 'detail.html'
    model = MyModel

    def get_object(self, queryset=None):
        return queryset.get(slug=self.slug)

我想像这样传递slug参数(或其他参数到视图)

MyView.as_view(slug='hello_world')

我是否需要重写任何方法才能做到这一点?

I have a custom class-based view

# myapp/views.py
from django.views.generic import *

class MyView(DetailView):
    template_name = 'detail.html'
    model = MyModel

    def get_object(self, queryset=None):
        return queryset.get(slug=self.slug)

I want to pass in the slug parameter (or other parameters to the view) like this

MyView.as_view(slug='hello_world')

Do I need to override any methods to be able to do this?


回答 0

如果您的urlconf看起来像这样:

url(r'^(?P<slug>[a-zA-Z0-9-]+)/$', MyView.as_view(), name = 'my_named_view')

那么该子弹将在您的视图函数(例如“ get_queryset”)中可用,如下所示:

self.kwargs['slug']

If your urlconf looks something like this:

url(r'^(?P<slug>[a-zA-Z0-9-]+)/$', MyView.as_view(), name = 'my_named_view')

then the slug will be available inside your view functions (such as ‘get_queryset’) like this:

self.kwargs['slug']

回答 1

传递给该as_view方法的每个参数都是View类的实例变量。这意味着要添加slug作为参数,您必须在子类中将其创建为实例变量:

# myapp/views.py
from django.views.generic import DetailView

class MyView(DetailView):
    template_name = 'detail.html'
    model = MyModel
    # additional parameters
    slug = None

    def get_object(self, queryset=None):
        return queryset.get(slug=self.slug)

那应该 MyView.as_view(slug='hello_world')起作用。

如果您通过关键字传递变量,请使用Erikkson先生建议的内容:https ://stackoverflow.com/a/11494666/9903

Every parameter that’s passed to the as_view method is an instance variable of the View class. That means to add slug as a parameter you have to create it as an instance variable in your sub-class:

# myapp/views.py
from django.views.generic import DetailView

class MyView(DetailView):
    template_name = 'detail.html'
    model = MyModel
    # additional parameters
    slug = None

    def get_object(self, queryset=None):
        return queryset.get(slug=self.slug)

That should make MyView.as_view(slug='hello_world') work.

If you’re passing the variables through keywords, use what Mr Erikkson suggested: https://stackoverflow.com/a/11494666/9903


回答 2

值得注意的是,您不需要重写get_object()即可基于作为关键字arg传递的段来查找对象-您可以使用SingleObjectMixin https://docs.djangoproject.com/en/1.5/ref/基于类的视图/ mixins-单个对象/#singleobjectmixin

# views.py
class MyView(DetailView):
    model = MyModel
    slug_field = 'slug_field_name'
    slug_url_kwarg = 'model_slug'
    context_object_name = 'my_model'

# urls.py
url(r'^(?P<model_slug>[\w-]+)/$', MyView.as_view(), name = 'my_named_view')

# mymodel_detail.html
{{ my_model.slug_field_name }}

(都slug_fieldslug_url_kwarg默认'slug'

It’s worth noting you don’t need to override get_object() in order to look up an object based on a slug passed as a keyword arg – you can use the attributes of a SingleObjectMixin https://docs.djangoproject.com/en/1.5/ref/class-based-views/mixins-single-object/#singleobjectmixin

# views.py
class MyView(DetailView):
    model = MyModel
    slug_field = 'slug_field_name'
    slug_url_kwarg = 'model_slug'
    context_object_name = 'my_model'

# urls.py
url(r'^(?P<model_slug>[\w-]+)/$', MyView.as_view(), name = 'my_named_view')

# mymodel_detail.html
{{ my_model.slug_field_name }}

(both slug_field and slug_url_kwarg default to 'slug')


回答 3

如果要向模板的上下文中添加对象,则可以覆盖get_context_data并添加到其上下文中。如果您需要request.user,那么请求也是自我的一部分。

def get_context_data(self, **kwargs):
        context = super(MyTemplateView, self).get_context_data(**kwargs)
        if 'slug' in self.kwargs:
            context['object'] = get_object_or_404(MyObject, slug=self.kwargs['slug'])
            context['objects'] = get_objects_by_user(self.request.user)

        return context

If you want to add an object to the context for the template you can override get_context_data and add to its context. The request is also a part of self in case you need the request.user.

def get_context_data(self, **kwargs):
        context = super(MyTemplateView, self).get_context_data(**kwargs)
        if 'slug' in self.kwargs:
            context['object'] = get_object_or_404(MyObject, slug=self.kwargs['slug'])
            context['objects'] = get_objects_by_user(self.request.user)

        return context

回答 4

您可以从urls.py https://docs.djangoproject.com/en/1.7/topics/http/urls/#passing-extra-options-to-view-functions传递参数

这也适用于通用视图。例:

url(r'^$', views.SectionView.as_view(), { 'pk': 'homepage', 'another_param':'?'}, name='main_page'),

在这种情况下,传递给视图的参数不必一定是View类的实例变量。使用此方法,您无需将默认页面名称硬编码到YourView模型中,而只需将其作为参数从urlconf中传递即可。

You can pass parameters from urls.py https://docs.djangoproject.com/en/1.7/topics/http/urls/#passing-extra-options-to-view-functions

This also works for generic views. Example:

url(r'^$', views.SectionView.as_view(), { 'pk': 'homepage', 'another_param':'?'}, name='main_page'),

In this case the parameters passed to the view should not necessarily be instance variables of the View class. Using this method you don’t need to hardcode default page name into YourView model, but you can just pass it as a parameter from urlconf.


回答 5

Yaroslav Nikitenko所述,如果您不想将新的实例变量硬编码到View类,则可以传递额外的选项来查看函数urls.py如下所示:

url(r'^$', YourView.as_view(), {'slug': 'hello_world'}, name='page_name')

我只想从视图中添加如何使用它。您可以实现以下方法之一:

# If slug is optional
def the_function(self, request, slug=None):
    # use slug here

# if slug is an optional param among others
def the_function(self, request, **kwargs):
    slug = kwargs.get("slug", None)
    other_param = kwargs.get("other_param", None)

# If slug is required
def the_function(self, request, slug):
    # use slug here

As stated by Yaroslav Nikitenko, if you don’t want to hardcode a new instance variable to the View class, you can pass extra options to view functions from urls.py like this:

url(r'^$', YourView.as_view(), {'slug': 'hello_world'}, name='page_name')

I just wanted to add how to use it from the view. You can implement one of the following methods:

# If slug is optional
def the_function(self, request, slug=None):
    # use slug here

# if slug is an optional param among others
def the_function(self, request, **kwargs):
    slug = kwargs.get("slug", None)
    other_param = kwargs.get("other_param", None)

# If slug is required
def the_function(self, request, slug):
    # use slug here

回答 6

对于django 3.0,这对我有用:

# myapp/views.py
from django.views.generic import DetailView

class MyView(DetailView):
    template_name = 'detail.html'
    slug = None

    def get_object(self, queryset=None):
        self.slug = self.kwargs.get('slug', None)
        return queryset.get(slug=self.slug)

# myapp/urls.py
from django.urls import path
from . import views

urlpatterns = [
    path('slug/<slug:slug>/', views.MyView.as_view(), name='myview_by_tag'),
]

For django 3.0, this is what worked for me:

# myapp/views.py
from django.views.generic import DetailView

class MyView(DetailView):
    template_name = 'detail.html'
    slug = None

    def get_object(self, queryset=None):
        self.slug = self.kwargs.get('slug', None)
        return queryset.get(slug=self.slug)

# myapp/urls.py
from django.urls import path
from . import views

urlpatterns = [
    path('slug/<slug:slug>/', views.MyView.as_view(), name='myview_by_tag'),
]

django模板中的“ none”是什么意思?

问题:django模板中的“ none”是什么意思?

我想看看Django模板中是否没有字段/变量。正确的语法是什么?

这是我目前拥有的:

{% if profile.user.first_name is null %}
  <p> -- </p>
{% elif %}
  {{ profile.user.first_name }} {{ profile.user.last_name }}
{% endif%}

在上面的示例中,我将用什么来替换“空”?

I want to see if a field/variable is none within a Django template. What is the correct syntax for that?

This is what I currently have:

{% if profile.user.first_name is null %}
  <p> -- </p>
{% elif %}
  {{ profile.user.first_name }} {{ profile.user.last_name }}
{% endif%}

In the example above, what would I use to replace “null”?


回答 0

None, False and True所有这些都可在模板标记和过滤器中找到。None, False,空字符串('', "", """""")和空列表/元组False都由进行求值if,因此您可以轻松地执行

{% if profile.user.first_name == None %}
{% if not profile.user.first_name %}

提示:@fabiocerqueira是正确的,将逻辑留给模型,将模板限制为唯一的表示层,并计算模型中的内容。一个例子:

# someapp/models.py
class UserProfile(models.Model):
    user = models.OneToOneField('auth.User')
    # other fields

    def get_full_name(self):
        if not self.user.first_name:
            return
        return ' '.join([self.user.first_name, self.user.last_name])

# template
{{ user.get_profile.get_full_name }}

希望这可以帮助 :)

None, False and True all are available within template tags and filters. None, False, the empty string ('', "", """""") and empty lists/tuples all evaluate to False when evaluated by if, so you can easily do

{% if profile.user.first_name == None %}
{% if not profile.user.first_name %}

A hint: @fabiocerqueira is right, leave logic to models, limit templates to be the only presentation layer and calculate stuff like that in you model. An example:

# someapp/models.py
class UserProfile(models.Model):
    user = models.OneToOneField('auth.User')
    # other fields

    def get_full_name(self):
        if not self.user.first_name:
            return
        return ' '.join([self.user.first_name, self.user.last_name])

# template
{{ user.get_profile.get_full_name }}

Hope this helps :)


回答 1

您还可以使用其他内置模板 default_if_none

{{ profile.user.first_name|default_if_none:"--" }}

You can also use another built-in template default_if_none

{{ profile.user.first_name|default_if_none:"--" }}

回答 2

is运算符:Django 1.10中的新增功能

{% if somevar is None %}
  This appears if somevar is None, or if somevar is not found in the context.
{% endif %}

isoperator : New in Django 1.10

{% if somevar is None %}
  This appears if somevar is None, or if somevar is not found in the context.
{% endif %}

回答 3

看看yesno助手

例如:

{{ myValue|yesno:"itwasTrue,itWasFalse,itWasNone" }}

Look at the yesno helper

Eg:

{{ myValue|yesno:"itwasTrue,itWasFalse,itWasNone" }}

回答 4

{% if profile.user.first_name %}起作用(假设您也不想接受'')。

if在Python一般对待NoneFalse''[]{},…所有为假。

{% if profile.user.first_name %} works (assuming you also don’t want to accept '').

if in Python in general treats None, False, '', [], {}, … all as false.


回答 5

您还可以使用内置的模板过滤器default

如果value的值为False(例如None,一个空字符串,0,False);默认显示为“-”。

{{ profile.user.first_name|default:"--" }}

文档:https : //docs.djangoproject.com/en/dev/ref/templates/builtins/#default

You can also use the built-in template filter default:

If value evaluates to False (e.g. None, an empty string, 0, False); the default “–” is displayed.

{{ profile.user.first_name|default:"--" }}

Documentation: https://docs.djangoproject.com/en/dev/ref/templates/builtins/#default


回答 6

您可以尝试以下方法:

{% if not profile.user.first_name.value %}
  <p> -- </p>
{% else %}
  {{ profile.user.first_name }} {{ profile.user.last_name }}
{% endif %}

这样,您实际上是在检查表单字段first_name是否具有与其关联的任何值。见{{ field.value }}循环遍历Django文档形式的领域

我正在使用Django 3.0。

You could try this:

{% if not profile.user.first_name.value %}
  <p> -- </p>
{% else %}
  {{ profile.user.first_name }} {{ profile.user.last_name }}
{% endif %}

This way, you’re essentially checking to see if the form field first_name has any value associated with it. See {{ field.value }} in Looping over the form’s fields in Django Documentation.

I’m using Django 3.0.


Django可选的url参数

问题:Django可选的url参数

我有一个像这样的Django URL:

url(
    r'^project_config/(?P<product>\w+)/(?P<project_id>\w+)/$',
    'tool.views.ProjectConfig',
    name='project_config'
),

views.py:

def ProjectConfig(request, product, project_id=None, template_name='project.html'):
    ...
    # do stuff

问题是我希望project_id参数是可选的。

我希望/project_config/并且/project_config/12345abdce/成为同等有效的URL模式,以便如果 project_id通过,那么我可以使用它。

就目前而言,访问不带project_id参数的URL时会得到404 。

I have a Django URL like this:

url(
    r'^project_config/(?P<product>\w+)/(?P<project_id>\w+)/$',
    'tool.views.ProjectConfig',
    name='project_config'
),

views.py:

def ProjectConfig(request, product, project_id=None, template_name='project.html'):
    ...
    # do stuff

The problem is that I want the project_id parameter to be optional.

I want /project_config/ and /project_config/12345abdce/ to be equally valid URL patterns, so that if project_id is passed, then I can use it.

As it stands at the moment, I get a 404 when I access the URL without the project_id parameter.


回答 0

有几种方法。

一种是在正则表达式中使用非捕获组:使正则 (?:/(?P<title>[a-zA-Z]+)/)?
表达式Django URL令牌为可选

另一种更容易遵循的方法是拥有多个符合您需求的规则,所有规则都指向同一视图。

urlpatterns = patterns('',
    url(r'^project_config/$', views.foo),
    url(r'^project_config/(?P<product>\w+)/$', views.foo),
    url(r'^project_config/(?P<product>\w+)/(?P<project_id>\w+)/$', views.foo),
)

请记住,在您看来,您还需要为可选的URL参数设置默认值,否则会出现错误:

def foo(request, optional_parameter=''):
    # Your code goes here

There are several approaches.

One is to use a non-capturing group in the regex: (?:/(?P<title>[a-zA-Z]+)/)?
Making a Regex Django URL Token Optional

Another, easier to follow way is to have multiple rules that matches your needs, all pointing to the same view.

urlpatterns = patterns('',
    url(r'^project_config/$', views.foo),
    url(r'^project_config/(?P<product>\w+)/$', views.foo),
    url(r'^project_config/(?P<product>\w+)/(?P<project_id>\w+)/$', views.foo),
)

Keep in mind that in your view you’ll also need to set a default for the optional URL parameter, or you’ll get an error:

def foo(request, optional_parameter=''):
    # Your code goes here

回答 1

您可以使用嵌套路线

Django <1.8

urlpatterns = patterns(''
    url(r'^project_config/', include(patterns('',
        url(r'^$', ProjectConfigView.as_view(), name="project_config")
        url(r'^(?P<product>\w+)$', include(patterns('',
            url(r'^$', ProductView.as_view(), name="product"),
            url(r'^(?P<project_id>\w+)$', ProjectDetailView.as_view(), name="project_detail")
        ))),
    ))),
)

Django> = 1.8

urlpatterns = [
    url(r'^project_config/', include([
        url(r'^$', ProjectConfigView.as_view(), name="project_config")
        url(r'^(?P<product>\w+)$', include([
            url(r'^$', ProductView.as_view(), name="product"),
            url(r'^(?P<project_id>\w+)$', ProjectDetailView.as_view(), name="project_detail")
        ])),
    ])),
]

这比DRY要多得多(假设您要将productkwarg 重命名为product_id,只需更改第4行,它就会影响以下网址。

针对Django 1.8及更高版本进行了编辑

You can use nested routes

Django <1.8

urlpatterns = patterns(''
    url(r'^project_config/', include(patterns('',
        url(r'^$', ProjectConfigView.as_view(), name="project_config")
        url(r'^(?P<product>\w+)$', include(patterns('',
            url(r'^$', ProductView.as_view(), name="product"),
            url(r'^(?P<project_id>\w+)$', ProjectDetailView.as_view(), name="project_detail")
        ))),
    ))),
)

Django >=1.8

urlpatterns = [
    url(r'^project_config/', include([
        url(r'^$', ProjectConfigView.as_view(), name="project_config")
        url(r'^(?P<product>\w+)$', include([
            url(r'^$', ProductView.as_view(), name="product"),
            url(r'^(?P<project_id>\w+)$', ProjectDetailView.as_view(), name="project_detail")
        ])),
    ])),
]

This is a lot more DRY (Say you wanted to rename the product kwarg to product_id, you only have to change line 4, and it will affect the below URLs.

Edited for Django 1.8 and above


回答 2

更简单的是使用:

(?P<project_id>\w+|)

“(a | b)”表示a或b,因此在您的情况下将是一个或多个文字字符(\ w +)或什么都没有。

因此,它看起来像:

url(
    r'^project_config/(?P<product>\w+)/(?P<project_id>\w+|)/$',
    'tool.views.ProjectConfig',
    name='project_config'
),

Even simpler is to use:

(?P<project_id>\w+|)

The “(a|b)” means a or b, so in your case it would be one or more word characters (\w+) or nothing.

So it would look like:

url(
    r'^project_config/(?P<product>\w+)/(?P<project_id>\w+|)/$',
    'tool.views.ProjectConfig',
    name='project_config'
),

回答 3

Django> 2.0版本

该方法与Yuji’Tomita’Tomita’s Answer中给出的方法基本相同。但是,受影响的语法是:

# URLconf
...

urlpatterns = [
    path(
        'project_config/<product>/',
        views.get_product, 
        name='project_config'
    ),
    path(
        'project_config/<product>/<project_id>/',
        views.get_product,
        name='project_config'
    ),
]


# View (in views.py)
def get_product(request, product, project_id='None'):
    # Output the appropriate product
    ...

使用,path()您还可以使用类型为的可选参数将额外的参数传递给视图。在这种情况下,您的视图不需要该属性的默认值:kwargsdictproject_id

    ...
    path(
        'project_config/<product>/',
        views.get_product,
        kwargs={'project_id': None},
        name='project_config'
    ),
    ...

有关如何在最新的Django版本中完成此操作的信息,请参阅有关URL调度的官方文档

Django > 2.0 version:

The approach is essentially identical with the one given in Yuji ‘Tomita’ Tomita’s Answer. Affected, however, is the syntax:

# URLconf
...

urlpatterns = [
    path(
        'project_config/<product>/',
        views.get_product, 
        name='project_config'
    ),
    path(
        'project_config/<product>/<project_id>/',
        views.get_product,
        name='project_config'
    ),
]


# View (in views.py)
def get_product(request, product, project_id='None'):
    # Output the appropriate product
    ...

Using path() you can also pass extra arguments to a view with the optional argument kwargs that is of type dict. In this case your view would not need a default for the attribute project_id:

    ...
    path(
        'project_config/<product>/',
        views.get_product,
        kwargs={'project_id': None},
        name='project_config'
    ),
    ...

For how this is done in the most recent Django version, see the official docs about URL dispatching.


回答 4

以为我会在答案中加点。

如果您有多个URL定义,则必须分别命名每个。因此,当调用反向时,您会失去灵活性,因为一个反向将需要一个参数,而另一个则不会。

使用正则表达式来容纳可选参数的另一种方法:

r'^project_config/(?P<product>\w+)/((?P<project_id>\w+)/)?$'

Thought I’d add a bit to the answer.

If you have multiple URL definitions then you’ll have to name each of them separately. So you lose the flexibility when calling reverse since one reverse will expect a parameter while the other won’t.

Another way to use regex to accommodate the optional parameter:

r'^project_config/(?P<product>\w+)/((?P<project_id>\w+)/)?$'

回答 5

的Django = 2.2

urlpatterns = [
    re_path(r'^project_config/(?:(?P<product>\w+)/(?:(?P<project_id>\w+)/)/)?$', tool.views.ProjectConfig, name='project_config')
]

Django = 2.2

urlpatterns = [
    re_path(r'^project_config/(?:(?P<product>\w+)/(?:(?P<project_id>\w+)/)/)?$', tool.views.ProjectConfig, name='project_config')
]

回答 6

用 ?工作正常,您可以检查pythex。请记住在视图方法的定义中添加参数* args和** kwargs

url('project_config/(?P<product>\w+)?(/(?P<project_id>\w+/)?)?', tool.views.ProjectConfig, name='project_config')

Use ? work well, you can check on pythex. Remember to add the parameters *args and **kwargs in the definition of the view methods

url('project_config/(?P<product>\w+)?(/(?P<project_id>\w+/)?)?', tool.views.ProjectConfig, name='project_config')

类没有对象成员

问题:类没有对象成员

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

该函数的第一行在出现错误Question.objects.all()

E1101:类“问题”没有对象“成员”

我正在阅读Django文档教程,并且它们具有相同的代码并正在运行。

我尝试调用实例。

Question = new Question()
and using MyModel.objects.all()

我的models.py类代码也是这个…

class Question(models.Model):
question_text = models.CharField(max_length = 200)
pub_date = models.DateTimeField('date published') 

def was_published_recently(self):
    return self.pub_date >= timezone.now() - datetime.timedelta(days=1)

def __str__(self):
    return self.question_text

无济于事,我仍然有此错误。

我已经读过有关pylint的文章,并进行了…

pylint --load-plugins pylint_django

这没有帮助,即使github自述文件说…

防止有关Django生成的属性(例如Model.objects或Views.request)的警告。

我在我的virtualenv中运行了命令,但是什么也没有。

因此,任何帮助都会很棒。

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

The first line of that function gets an error on Question.objects.all():

E1101: Class ‘Question’ has no objects ‘member’

I’m following the Django documentation tutorial and they have the same code up and running.

I have tried calling an instance.

Question = new Question()
and using MyModel.objects.all()

Also my models.py code for that class is this…

class Question(models.Model):
    question_text = models.CharField(max_length = 200)
    pub_date = models.DateTimeField('date published') 

    def was_published_recently(self):
        return self.pub_date >= timezone.now() - datetime.timedelta(days=1)

    def __str__(self):
        return self.question_text

To no avail I still have this error.

I have read about pylint and ran this…

pylint --load-plugins pylint_django

Which didn’t help, even tho the github readme file says…

Prevents warnings about Django-generated attributes such as Model.objects or Views.request.

I ran the command within my virtualenv, and yet nothing.

So any help would be great.


回答 0

pylint-django使用pip如下安装

pip install pylint-django

然后在Visual Studio Code中转到:用户设置Ctrl+ ,或文件>首选项>设置(如果可用))放入以下内容(请注意VSC中自定义用户设置所需的花括号):

{"python.linting.pylintArgs": [
     "--load-plugins=pylint_django"
],}

Install pylint-django using pip as follows

pip install pylint-django

Then in Visual Studio Code goto: User Settings (Ctrl + , or File > Preferences > Settings if available ) Put in the following (please note the curly braces which are required for custom user settings in VSC):

{"python.linting.pylintArgs": [
     "--load-plugins=pylint_django"
],}

回答 1

@ tieuminh2510的答案是完美的。但是在较新版本的VSC中,您将找不到在用户设置中编辑或粘贴该命令的选项。现在以较新的版本添加该代码,请按照以下步骤操作

ctr + sft + P打开“ 命令面板”。现在,在命令面板中键入首选项:配置特定语言的设置。现在选择Python。在右侧粘贴此代码

"python.linting.pylintArgs": [
        "--load-plugins=pylint_django",
    ]

里面第一个大括号。确保pylint-django

希望这会有所帮助!

@tieuminh2510 answer is perfect. But in newer versions of VSC you will not find thhe option to edit or paste that command in User Settings. Now in newer version to add that code follow this steps :

Press ctr+sft+P to open the the Command Palette. Now in command palette type Preferences: Configure Language Specific Settings. Now select Python. Here in right side paste this code

"python.linting.pylintArgs": [
        "--load-plugins=pylint_django",
    ]

Inside the first curly braces. Make sure that pylint-django.

Hope this will help!


回答 2

安装Django pylint:

pip install pylint-django

ctrl + shift + p>首选项:配置特定于语言的设置> Python

适用于python语言的settings.json应该如下所示:

{
    "python.linting.pylintArgs": [
        "--load-plugins=pylint_django"
    ],

    "[python]": {

    }
}

Install Django pylint:

pip install pylint-django

ctrl+shift+p > Preferences: Configure Language Specific Settings > Python

The settings.json available for python language should look like the below:

{
    "python.linting.pylintArgs": [
        "--load-plugins=pylint_django"
    ],

    "[python]": {

    }
}

回答 3

这是答案。从我的reddit帖子中获得… https://www.reddit.com/r/django/comments/6nq0bq/class_question_has_no_objects_member/

这不是错误,只是来自VSC的警告。Django会动态地将该属性添加到所有模型类中(它在幕后使用了很多魔法),因此IDE不会通过查看类声明来了解该属性,因此会警告您可能存在的错误(不是)。对象实际上是一个帮助查询数据库的Manager实例。如果您真的想摆脱该警告,则可以转到所有模型并添加object = models.Manager()现在,VSC将看到声明的对象,并且不会再次抱怨。

Heres the answer. Gotten from my reddit post… https://www.reddit.com/r/django/comments/6nq0bq/class_question_has_no_objects_member/

That’s not an error, it’s just a warning from VSC. Django adds that property dynamically to all model classes (it uses a lot of magic under the hood), so the IDE doesn’t know about it by looking at the class declaration, so it warns you about a possible error (it’s not). objects is in fact a Manager instance that helps with querying the DB. If you really want to get rid of that warning you could go to all your models and add objects = models.Manager() Now, VSC will see the objects declared and will not complain about it again.


回答 4

我已经尝试了所有可能的解决方案,但不幸的是,我的vscode设置不会更改其linter路径。因此,我尝试在设置>用户设置> python中探索vscode设置。找到Linting:Pylint路径并将其更改为“ pylint_django”。别忘了在设置>用户设置> python配置中将linter更改为“ pylint_django”,从“ pyLint”更改为“ pylint_django”。

I’ve tried all possible solutions offered but unluckly my vscode settings won’t changed its linter path. So, I tride to explore vscode settings in settings > User Settings > python. Find Linting: Pylint Path and change it to “pylint_django”. Don’t forget to change the linter to “pylint_django” at settings > User Settings > python configuration from “pyLint” to “pylint_django”.


回答 5

VS CODE 1.40.0的更新

完成后:

$ pip install pylint-django

请点击以下链接:https : //code.visualstudio.com/docs/python/linting#_default-pylint-rules

请注意,要pylint考虑的方法pylint-django是通过指定:

"python.linting.pylintArgs": ["--load-plugins", "pylint_django"]

settings.jsonVS Code中。

但是之后,您会发现很多新的掉毛错误。然后,阅读此处的内容:

只要将python.linting.pylintUseMinimalCheckers设置为true(默认值),就会传递这些参数。如果在中指定值pylintArgs或使用Pylint配置文件(请参阅下一节),则将pylintUseMinimalCheckers其隐式设置为false

我所做的就是.pylintrc按照链接中的描述创建一个文件,然后在文件中配置以下参数(不影响文件的其余部分):

load-plugins=pylint_django

disable=all

enable=F,E,unreachable,duplicate-key,unnecessary-semicolon,global-variable-not-assigned,unused-variable,binary-op-exception,bad-format-string,anomalous-backslash-in-string,bad-open-mode

现在pylint可以正常工作了。

UPDATE FOR VS CODE 1.40.0

After doing:

$ pip install pylint-django

Follow this link: https://code.visualstudio.com/docs/python/linting#_default-pylint-rules

Notice that the way to make pylint have into account pylint-django is by specifying:

"python.linting.pylintArgs": ["--load-plugins", "pylint_django"]

in the settings.json of VS Code.

But after that, you will notice a lot of new linting errors. Then, read what it said here:

These arguments are passed whenever the python.linting.pylintUseMinimalCheckers is set to true (the default). If you specify a value in pylintArgs or use a Pylint configuration file (see the next section), then pylintUseMinimalCheckers is implicitly set to false.

What I have done is creating a .pylintrc file as described in the link, and then, configured the following parameters inside the file (leaving the rest of the file untouched):

load-plugins=pylint_django

disable=all

enable=F,E,unreachable,duplicate-key,unnecessary-semicolon,global-variable-not-assigned,unused-variable,binary-op-exception,bad-format-string,anomalous-backslash-in-string,bad-open-mode

Now pylint works as expected.


回答 6

您可以将linter for Python扩展更改为Visual Studio Code。

在VS中,打开命令面板Ctrl + Shift + P并键入以下命令之一:

Python:选择Linter

当您选择短绒时,它将被安装。我尝试了flake8,看来问题已解决。

You can change the linter for Python extension for Visual Studio Code.

In VS open the Command Palette Ctrl+Shift+P and type in one of the following commands:

Python: Select Linter

when you select a linter it will be installed. I tried flake8 and it seems issue resolved for me.


回答 7

只需添加@ Mallory-Erik所说的话:您可以将objects = models.Manager()其放在模式中:

class Question(models.Model):
    # ...
    def was_published_recently(self):
        return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
    # ...
    def __str__(self):
        return self.question_text
    question_text = models.CharField(max_length = 200)
    pub_date = models.DateTimeField('date published')
    objects = models.Manager()

Just adding on to what @Mallory-Erik said: You can place objects = models.Manager() it in the modals:

class Question(models.Model):
    # ...
    def was_published_recently(self):
        return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
    # ...
    def __str__(self):
        return self.question_text
    question_text = models.CharField(max_length = 200)
    pub_date = models.DateTimeField('date published')
    objects = models.Manager()

回答 8

首先使用以下命令安装pylint-django

$ pip install pylint-django

然后运行第二条命令,如下所示:

$ pylint test_file.py --load-plugins pylint_django

–load-plugins pylint_django是正确检查django代码所必需的

First install pylint-django using following command

$ pip install pylint-django

Then run the second command as follows:

$ pylint test_file.py --load-plugins pylint_django

–load-plugins pylint_django is necessary for correctly review a code of django


回答 9

如果您使用python 3

python3 -m pip install pylint-django

如果python <3

python -m pip install pylint-django==0.11.1

注意:2.0版要求pylint> = 2.0,该版本不再支持Python 2!(https://pypi.org/project/pylint-django/

If you use python 3

python3 -m pip install pylint-django

If python < 3

python -m pip install pylint-django==0.11.1

NOTE: Version 2.0, requires pylint >= 2.0 which doesn’t support Python 2 anymore! (https://pypi.org/project/pylint-django/)


回答 10

通过执行操作Question = new Question()(我假设new是错字),您将用的实例覆盖Question模型Question。就像Sayse在评论中所说:不要为变量使用与模型名称相同的名称。因此,将其更改为类似my_question = Question()

By doing Question = new Question() (I assume the new is a typo) you are overwriting the Question model with an intance of Question. Like Sayse said in the comments: don’t use the same name for your variable as the name of the model. So change it to something like my_question = Question().


回答 11

如何抑制特定于每个错误的每一行上的错误?

像这样的东西:https : //pylint.readthedocs.io/en/latest/user_guide/message-control.html

错误:[pylint]类’class_name’没有’member_name’成员可以通过以下方法在该行上取消显示:

  # pylint: disable=no-member

How about suppressing errors on each line specific to each error?

Something like this: https://pylint.readthedocs.io/en/latest/user_guide/message-control.html

Error: [pylint] Class ‘class_name’ has no ‘member_name’ member It can be suppressed on that line by:

  # pylint: disable=no-member

回答 12

将您的linter更改为-flake8,问题将消失。

Change your linter to – flake8 and problem will go away.


回答 13

当我使用pylint_runner时发生此问题

所以我要做的是打开.pylintrc文件并将其添加

# List of members which are set dynamically and missed by pylint inference
# system, and so shouldn't trigger E1101 when accessed. Python regular
# expressions are accepted.
generated-members=objects

This issue happend when I use pylint_runner

So what I do is open .pylintrc file and add this

# List of members which are set dynamically and missed by pylint inference
# system, and so shouldn't trigger E1101 when accessed. Python regular
# expressions are accepted.
generated-members=objects

回答 14

我能够更新用户settings.json

在我的Mac上,它存储在:

~/Library/Application Support/Code/User/settings.json

在其中设置以下内容:

{
    "python.linting.pycodestyleEnabled": true,
    "python.linting.pylintEnabled": true,
    "python.linting.pylintPath": "pylint",
    "python.linting.pylintArgs": ["--load-plugins", "pylint_django"]
}

那为我解决了这个问题。

I was able to update the user settings.json

On my mac it was stored in:

~/Library/Application Support/Code/User/settings.json

Within it, I set the following:

{
    "python.linting.pycodestyleEnabled": true,
    "python.linting.pylintEnabled": true,
    "python.linting.pylintPath": "pylint",
    "python.linting.pylintArgs": ["--load-plugins", "pylint_django"]
}

That solved the issue for me.