How can I access primary key in template tag?

Question:

I am trying to create an update view that allows users to update their data. I am trying to access the data by using primary keys. My problem is that I do not know the syntax to implement it.

models.py

class Detail(models.Model):
    """
    This is the one for model.py
    """
    username = models.ForeignKey(User, on_delete=models.CASCADE, null=True, default="")
    matricno = models.CharField(max_length=9, default="")
    email = models.EmailField(default="")
    first_name = models.CharField(max_length=200, default="")
    last_name = models.CharField(max_length=255, default="")

    class Meta:
        verbose_name_plural = "Detail"

    def __str__(self):
        return self.first_name+ " "+self.last_name

views.py

def success(request):
    return render(request, "success.html", {})

@login_required(login_url="signin")
def details(request):
    form = Details()
    if request.method == "POST":
        form = Details(request.POST)
        if form.is_valid():
            detail = form.save(commit=False)
            detail.username = request.user
            detail.save()
            return redirect(success)
    else:
        form = Details(initial={"matricno":request.user.username})
    return render(request, "details.html", {"form":form})

def updatedetails(request, pk):
    detail = Detail.objects.get(id=pk)
    form = Details(instance=detail)
    if request.method == "POST":
        form = Details(request.POST, instance=detail)
        if form.is_valid():
            form.save()
            return redirect(success)
    return render(request, "details.html", {"form":form})

urls.py

from django.urls import path

from . import views

urlpatterns = [
    path("details/", views.details, name="details"),
    path("success/", views.success, name="success"),
    path("edit/<str:pk>/", views.updatedetails, name="updatedetails"),
]

my html template

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Success</title>
</head>
<body>
    <h1>Thank You for Filling Out the Form</h1>
    <p><a href="/edit/{{request.detail.id}}/">Click Here To Edit</a></p>
</body>
</html>

So what I am trying to figure out is how to call the primary key in my template.

Asked By: Olasubomi

||

Answers:

Try using

href="{% url 'updatedetails' pk=request.detail.id %}"

Let me know if that works. This will look for the path name updatedetails located in your urlpatterns and provide the id as the key. I’m somewhat new at this also, so i’m hoping this helps and is correct.

Answered By: s-knocks

At first, I’d recommend you to change <str:pk> to <int:pk> in updatedetails path so urls.py should be:

from django.urls import path

from . import views

urlpatterns = [
    path("details/", views.details, name="details"),
    path("success/<int:pk>/", views.success, name="success"),
    path("edit/<int:pk>/", views.updatedetails, name="updatedetails"),
]

Secondly, I’d recommend you to use get_object_or_404() instead of get() and also if you see it correctly you are also missing "" in redirect(success) that should be redirect("success") so views.py should be:

from django.shortcuts import get_object_or_404

def updatedetails(request, pk):
    detail = get_object_or_404(Detail,id=pk)
    form = Details(instance=detail)
    if request.method == "POST":
        form = Details(request.POST, instance=detail)
        if form.is_valid():
            form.save()
            return redirect("success", args=(pk))
    return render(request, "details.html", {"form":form})

@login_required(login_url="signin")
def details(request):
    form = Details()
    if request.method == "POST":
        form = Details(request.POST)
        if form.is_valid():
            detail = form.save(commit=False)
            detail.username = request.user
            detail.save()
            return redirect(success,args=(detail.id))
    else:
        form = Details(initial={"matricno":request.user.username})
    return render(request, "details.html", {"form":form})


def success(request,pk):
    
    return render(request, "success.html", {"id":pk})

Then, in the template you can use url tags and pass id to updatedetails view as:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Success</title>
</head>
<body>
    <h1>Thank You for Filling Out the Form</h1>
    <p><a href="{% url 'updatedetails' id %}">Click Here To Edit</a></p>
</body>
</html>
Answered By: Sunderam Dubey

Answer to the original question

How can I access primary key in template tag?

Well, you have to pass it to the view that renders the template, either through the context, or in this case, since you need it in the success page, which you are getting to via a redirect, send it as a parameter in your redirect.

Second, if you are trying to create a form from a model, then use a ModelForm. This you do not do just by setting a form variable equal to a model instance. You do this by creating a file called forms.py:

# forms.py

from django.forms import ModelForm
from .models import Detail

class DetailForm(ModelForm):
    class Meta:
        model = Detail
        # Include below the fields from the Detail model you
        # would like to include in your form
        fields = ['username', 'matricno', 'email', 'first_name', 'last_name', ]

Then in your views you can access this form:

#views.py

from .models import Detail
from .forms import DetailForm

def success(request, pk):
    # NOTE that here you must receive the pk
    return render(request, "success.html", {'pk': pk})

@login_required(login_url="signin")
def details(request):
    form = DetailForm()
    if request.method == "POST":
        form = DetailForm(request.POST)
        if form.is_valid():
            detail = form.save(commit=False)
            detail.username = request.user
            detail.save()
            # NOTE: here you can send the detail primary key, pk, or id
            # to the success view where you are trying to use it
            return redirect('success', pk=detail.pk)
    else:
        form = Details(initial={"matricno": request.user.username})
    return render(request, "details.html", {"form": form})

def updatedetails(request, pk):
    detail = Detail.objects.get(id=pk)
    form = DetailForm(instance=detail)
    if request.method == "POST":
        form = Details(request.POST, instance=detail)
        if form.is_valid():
            form.save()
            return redirect('success', pk=detail.pk)
    return render(request, "details.html", {"form":form})

Note how you can send the primary key to the success template in the redirect. That is the answer to the original question.

Now you can access the primary in your template simply:

<!--html template -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Success</title>
</head>
<body>
    <h1>Thank You for Filling Out the Form</h1>
    <p><a href="{% url 'updatedetails' pk %}">Click Here To Edit</a></p>
</body>
</html>

Since the success view needed to be changed to get the primary key, we have to modify the urls.py so that it can receive it:

# urls.py
from django.urls import path

from . import views

urlpatterns = [
    path("details/", views.details, name="details"),
    path("success/<int:pk>/", views.success, name="success"),
    path("edit/<int:pk>/", views.updatedetails, name="updatedetails"),
]
Answered By: raphael