Generic detail view UserProfileDetailView must be called with either an object pk or a slug in the URLconf

Viewed 1217

Well I am facing error and it's now its been two days to this question and still stuck on this mistake, anybody can help and able to fix this. I am new in Django and need help. I shall be thankful. If any thing else requires for answers than tell me I will update my questions with that detail.. models.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 %}

snippets/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>

error traceback:

  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.
3 Answers

Problem

  1. str type used instead of slug type in urls.py
  2. UserProfileDetailView doesn't specify your custom slug_url_kwarg and slug_field
  3. UserProfileDetailView specifies UserProfile model but UserProfile model doesn't have attribute or method username, which is on `User table.

Solution

Reading Django's DetailView code, you'll find that the following is necessary to get your code working properly.

Update class attributes

views.py

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

Update UserProfile model OR Update 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`). Thus either:

  1. UserProfile model must have reference to username or;
  2. get_slug_field must explicitly define slug field or;
  3. get_slug_field must add functionality for dot syntax method traversal

models.py

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

OR

class UserProfileDetailView(DetailView):
    ...

    def get_slug_field(self):
        self.user.username

Update username type in urls.py

Helpful, but not necessary.

urls.py

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

References

Django Detail View get_slug_field (Github): https://github.com/django/django/blob/master/django/views/generic/detail.py#L78-L80

you need to add the user pk or slug in the url so that django can retrieve the user using this pk or slug so edit the url to be like this

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

but make sure that your slug equal the username of the user , to do this override the save method in your model to be like this

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

make sure to change 'Your_Model_Name' with your model class name

Set slug_url_kwarg--(Django Doc) and slug_field--(Django Doc) attributes on your view class


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
Related