1

I am having an issue with an url and regular expression I get the error

AttributeError: Generic detail view EmployeeDetailView must be called with either an object pk or a slug.

What I am to achieve is to get to a user detail page coming from a specific project

url(r'^project/(?P<pk>[0-9]+)/$',views.ProjectDetailView.as_view(), name='ProjectDetails'),
url(r'^project/(?P<pk1>[0-9]+)/(?P<pk2>[0-9]+)/$',views.EmployeeDetailView.as_view(), name='EmployeDetails'),

my view is :

Project detail :
class ProjectDetailView(generic.DetailView, LoginRequiredMixin):
    #import pdb; pdb.set_trace()
    model = Project
    template_name = 'project_details.html'

    def get_context_data(self, **kwargs):
        context = super(ProjectDetailView, self).get_context_data(**kwargs)
        try:
            team_name = Project.objects.get(id=self.kwargs['pk']).team_id.members.all()
            context['team_name'] = team_name
        except AttributeError:
            pass
        return context

class EmployeeDetailView(generic.DetailView, LoginRequiredMixin):
    #import pdb; pdb.set_trace()
    model = MyUser
    template_name = 'Employee_Details.html'

    def get_context_data(self, **kwargs):
        context = super(EmployeeDetailView, self).get_context_data(**kwargs)
        employee_name = MyUser.objects.get(id=self.kwargs['pk'])
        context['employee_name'] = employee_name
        return context

HTML link :

<span class="fa fa-id-card-o" aria-hidden="true"><a href="{% url 'website:EmployeDetails' pk1 = project.id pk2 = member.id %}"> Show Results</a>

models: MyUser models:

class MyUser(AbstractBaseUser):
    email = models.EmailField(
        verbose_name='email address',
        max_length=255,
        unique=True,
    )
    first_name = models.CharField(max_length=150, blank=True, null=True)
    last_name = models.CharField(max_length=150, blank=True, null=True)
    is_active = models.BooleanField(default=True)
    is_admin = models.BooleanField(default=False)
    is_hr = models.BooleanField(default=False)
    is_candidate = models.BooleanField(default=False)
    is_employee = models.BooleanField(default=False)
    company = models.CharField(max_length=100, blank=True, null=True)

Project model:

class Project(models.Model):
    name = models.CharField(max_length=250)
    team_id = models.ForeignKey(Team, blank=True, null=True)
    project_hr_admin = models.ForeignKey('registration.MyUser', blank=True, null=True)
    candidat_answers = models.ManyToManyField('survey.response')

Team models:

class Team(models.Model):
    team_name = models.CharField(max_length=100, default = '')
    team_hr_admin = models.ForeignKey(MyUser, blank=True, null=True)
    members = models.ManyToManyField(MyUser, related_name="members")

could you please help me to figure it ? thx you ;)

5
  • Usually, your URL pattern for a DetailView would contain a single group (?P<pk>[0-9]+). Django would use the pk from the URL to fetch the object with that ID. In your case you have (?P<pk1>[0-9]+) and (?P<pk2>[0-9]+), so Django doesn't know what to do. If the URL was /project/5/7/, what object do you want to see the detail for? Commented Dec 4, 2017 at 11:30
  • it would be project.id = 5 and member.id = 7; a member can be part of multiple project so I would like to see the detail of the member for this exact project Commented Dec 4, 2017 at 11:31
  • you have to set pk_url_kwarg to pk1 if pk1 is the MyUser object or pk2 if pk2 is MyUser object. docs.djangoproject.com/en/1.8/ref/class-based-views/… Commented Dec 4, 2017 at 11:32
  • @SandeepBalagopal Where do I have to set pk_url_kwarg exactly ? Commented Dec 4, 2017 at 11:34
  • Using related_name='members' is confusing. You are following the relationship backwards from MyUser to Team, so related_name='teams' would make more sense. Also you don't need _id in foreign key names - team would be better than team_id. Commented Dec 4, 2017 at 12:11

1 Answer 1

1

Django doesn't know how to use pk1 and pk2 to fetch the object for the view. I would override the get_object method and fetch the object there.

from django.shortcuts import get_object_or_404

# Note mixin should come first
class EmployeeDetailView(LoginRequiredMixin, generic.DetailView):
    model = MyUser
    template_name = 'Employee_Details.html'

    def get_object(self, queryset=None):
        return get_object_or_404(MyUser, pk=self.kwargs['pk2'], project=self.kwargs['pk1'])

    ...

Another option is to set pk_url_kwarg = 'pk2'. This tells Django that pk2 is the primary key of the MyUser object, so there is no need to override get_object. However if you do this, then Django will ignore the pk1 from the URL.

class EmployeeDetailView(generic.DetailView, LoginRequiredMixin):
    #import pdb; pdb.set_trace()
    model = MyUser
    pk_url_kwarg = 'pk2'
    template_name = 'Employee_Details.html'
Sign up to request clarification or add additional context in comments.

12 Comments

great I used pk_url_kwarg = 'pk2' and it worked .. would you recommend your option to be better ?
As I said, if you use pk_url_kwarg = 'pk2', then Django will ignore pk1. The URLs /project/5/7/` and /project/500/7/ will both show the object with pk=7, regardless of whether the project id is correct.
Oh ok ok so definitively option 1 is better could you explain employee=self.kwargs['pk1'] what is refered to employee ?
I should have written project=self.kwargs['pk1']. I'm assuming that your MyUser model has a foreign key project to the Project model. You haven't shown your models in the question so you may have to adjust that part of the code.
using project = self.kwargs I get :No MyUser matches the given query. I will add you my models ..
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.