通用详细视图 UserProfileDetailView 必须在 URLconf 中使用对象 pk 或 slug 调用

Posted

技术标签:

【中文标题】通用详细视图 UserProfileDetailView 必须在 URLconf 中使用对象 pk 或 slug 调用【英文标题】:Generic detail view UserProfileDetailView must be called with either an object pk or a slug in the URLconf 【发布时间】:2021-01-25 21:43:18 【问题描述】:

好吧,我遇到了错误,现在这个问题已经两天了,仍然坚持这个错误,任何人都可以提供帮助并能够解决这个问题。我是 Django 的新手,需要帮助。我将不胜感激。如果除了告诉我之外还有什么需要回答的,我会用这个细节更新我的问题。 模型.py

class UserProfile(models.Model):

    user = models.OneToOneField(User, on_delete=models.CASCADE)
    follower = models.ManyToManyField(User, related_name ='is_following',blank=True)
    avatar = models.ImageField(("Avatar"), upload_to='displays', default = '1.jpg',height_field=None, width_field=None, max_length=None,blank = True)
    create_date = models.DateField(auto_now_add=True,null=True)
   


    def __str__(self):
        return f'self.user.username'

views.py

class UserProfileDetailView(DetailView):

    model = UserProfile
    template_name = "profiles/userprofile_detail.html"

    def get_context_data(self,*args, **kwargs):
            context = super().get_context_data(*args,**kwargs) 
            is_following = False
            if self.object.user in self.request.user.userprofile.follower.all():
                is_following = True
            context["is_following"] = is_following
            return context

urls.py

urlpatterns = [
    # path('user',UserProfileCreateView.as_view(template_name = 'profiles/userprofile.html'),name='home')
    # path('user/',userprofile,name = 'home'),
     path('user-profile/',UserProfileFollowToggle.as_view(),name = 'toggle'),
    path('<str:username>/',UserProfileDetailView.as_view(),name = 'detail'),
]

userprofile_detail.html

% extends 'base.html' %
% block content %
<p style="text-align: center;"><img src=" object.user.userprofile.avatar.url " width = "50%"></p>
 request.user.userprofile.follower.all <br>
object.user.userprofile 
% if object.user in request.user.userprofile.follower.all  %
Following
% endif %
<p>% include 'profiles/snippets/follow_toggle.html' with username=user.username is_following=is_following %</p>
<h2> object.username </h2>
/is_following 
% endblock content %

sn-ps/follow_toggle.html

<form class='form' method='POST' action="% url 'profiles:toggle'%">
% csrf_token %
<input type='hidden' name='username' value="% if username % username % else %hello% endif %">
<button class='btn % if is_following %btn-warning% else %btn-primary% endif %'>% if is_following %Unfollow % else %Follow% endif %</button>
</form>

错误回溯:

  Environment:


Request Method: GET
Request URL: http://127.0.0.1:8000/profiles/testuser/

Django Version: 3.0.3
Python Version: 3.8.3
Installed Applications:
['django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'bootstrap3',
 'accounts',
 'posts',
 'profiles']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware']



Traceback (most recent call last):
  File "C:\Users\AHMED\anaconda3\lib\site-packages\django\core\handlers\exception.py", line 34, in inner
    response = get_response(request)
  File "C:\Users\AHMED\anaconda3\lib\site-packages\django\core\handlers\base.py", line 115, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "C:\Users\AHMED\anaconda3\lib\site-packages\django\core\handlers\base.py", line 113, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "C:\Users\AHMED\anaconda3\lib\site-packages\django\views\generic\base.py", line 71, in view
    return self.dispatch(request, *args, **kwargs)
  File "C:\Users\AHMED\anaconda3\lib\site-packages\django\views\generic\base.py", line 97, in dispatch
    return handler(request, *args, **kwargs)
  File "C:\Users\AHMED\anaconda3\lib\site-packages\django\views\generic\detail.py", line 106, in get
    self.object = self.get_object()
  File "C:\Users\AHMED\anaconda3\lib\site-packages\django\views\generic\detail.py", line 45, in get_object
    raise AttributeError(

Exception Type: AttributeError at /profiles/testuser/
Exception Value: Generic detail view UserProfileDetailView must be called with either an object pk or a slug in the URLconf.

【问题讨论】:

能否也添加您的用户模型的定义? 我正在使用来自djnago.contrib.auth.models import User的django内置用户模型 对不起,我的意思是 UserProfile 模型。在这种情况下,我假设 UserProfile 与 User 实例具有 OneToOne user 关系?如果是这样,请查看 docs.djangoproject.com/en/3.1/topics/db/examples/one_to_one 以及如何捕获 RelatedObjectDoesNotExist 异常。 是的,userprofile 与用户模型是一对一的关系 那就这样吧。您可能在没有为user 设置关系的情况下创建了 UserProfile 实例。我建议将其设为不可为空的字段 (null=False, blank=False) 以防止这种情况发生 - 没有 User 的 UserProfile 真的没有意义吗? 【参考方案1】:

问题

    在 urls.py 中使用 str 类型而不是 slug 类型 UserProfileDetailView 没有指定您的自定义 slug_url_kwargslug_field UserProfileDetailView 指定UserProfile 模型,但UserProfile 模型没有属性或方法username,它位于`用户表中。

解决方案

阅读 Django 的 DetailView 代码,你会发现以下是让你的代码正常工作所必需的。

更新类属性

views.py

class UserProfileDetailView(DetailView):
    slug_url_kwarg = "username"
    slug_field = "username"

更新 UserProfile 模型或更新 UserProfileDetailView.get_slug_field

UserProfile is the lookup table defined for UserProfileDetailView and get_slug_fieldmethod, which readsslug_fieldproperty on the UserProfileDetailView doesn't support dot syntax method traversal (ie:user.username`)。 因此,要么:

    UserProfile 模型必须引用username 或; get_slug_field 必须明确定义 slug 字段或; get_slug_field 必须添加点语法方法遍历的功能

models.py

class UserProfile(models.model):
    ...
    
    @property
    def username(self):
        self.user.username 

class UserProfileDetailView(DetailView):
    ...

    def get_slug_field(self):
        self.user.username

在 urls.py 中更新用户名类型

有帮助,但不是必需的。

urls.py

path('<slug:username>/', UserProfileDetailView.as_view(), name = 'detail'),

参考文献

Django 详细视图get_slug_field(Github):https://github.com/django/django/blob/master/django/views/generic/detail.py#L78-L80

【讨论】:

【参考方案2】:

您需要在 url 中添加用户 pk 或 slug 以便 django 可以使用此 pk 或 slug 检索用户 所以编辑网址是这样的

path('<slug:username>/',UserProfileDetailView.as_view(),name = 'detail'),

但要确保你的 slug 等于用户的用户名,这样做会覆盖你模型中的保存方法,就像这样

def save(self, *args, **kwargs): 
    self.slug = self.username
    super(Your_Model_Name, self).save(*args, **kwargs)  

确保使用您的模型类名称更改“Your_Model_Name”

【讨论】:

我如何设置 slug 等于用户名? 我必须在模型中添加这个吗? 是的,您需要在模型字段之后添加此方法,并确保将“您的模型名称”更改为您的模型名称,之后当您创建新用户时,slug 文件将自动获取用户名的值 不必要地跨表复制数据会损害数据完整性并增加维护开销。只需创建一个类属性即可。【参考方案3】:

在视图类上设置 slug_url_kwarg--(Django Doc) 和 slug_field--(Django Doc) 属性


class UserProfileDetailView(DetailView):
    slug_url_kwarg = "username" # this the `argument` in the URL conf
    slug_field = "your_model_field" # this is the model field name.

    # Rest of your code

【讨论】:

我这样做了,但现在它向我显示:ValueError at /profiles/testuser/ 字段 'id' 需要一个数字,但得到了 'testuser'。 您提供的slug_field 值是多少?添加完整的错误回溯。 @FlashMaddy 这还不够,因为用户名存在于 User 模型而不是 UserProfile 模型中 这就是slug_field 属性的作用。您可以将其设置为适当的 span field (使用双下划线)@pygeek

以上是关于通用详细视图 UserProfileDetailView 必须在 URLconf 中使用对象 pk 或 slug 调用的主要内容,如果未能解决你的问题,请参考以下文章

必须使用对象 pk 或 slug 调用通用详细视图 ProfileView

必须使用对象 pk 或 slug 调用通用详细视图结果

难以将 slug 添加到 Django 中的通用详细信息视图

通用详细视图 UserProfileDetailView 必须在 URLconf 中使用对象 pk 或 slug 调用

通用 iOS 应用程序:详细视图控制器中的 UIWebView 不显示 iPad 部分的内容

iPad SplitViewController 带有用于详细视图的单独导航堆栈