---
title: "Γράφοντας το πρώτο σας Django app, μέρος 3"
version: 2.2
locale: el
source: https://docs.djangoproject.com/el/2.2/intro/tutorial03/
canonical: https://djangodocs.dev/el/2.2/intro/tutorial03/
---
# Γράφοντας το πρώτο σας Django app, μέρος 3

Ο οδηγός αυτός ξεκινά εκεί που τελειώνει [ο οδηγός 2](/el/2.2/intro/tutorial02/). Συνεχίζουμε με την εφαρμογή μας (σκοπός μας είναι φτιάξουμε ένα σύστημα ψηφοφορίας όπου θα γράφουμε τις ερωτήσεις και τι πιθανές επιλογές και ο κόσμος θα μπορεί να ψηφίζει). Αυτή τη φορά θα επικεντρωθούμε στην προβολή της ιστοσελίδας μας στο ευρύ κοινό, στα “views”.

## Επισκόπηση

Ένα view είναι ένας «τύπος» μιας ιστοσελίδας (Web page) σε ένα Django application το οποίο, σε γενικές γραμμές, εξυπηρετεί μια συγκεκριμένη συνάρτηση και έχει ένα συγκεκριμένο template. Για παράδειγμα, ένα blog application, μπορεί να περιέχει τα ακόλουθα views:

- Blog homepage – προβάλει τα μερικά από τα τελευταία entries (καταχωρήσεις).
- Σελίδα «λεπτομερειών» μιας entry (καταχώρησης) – μια permalink σελίδα για ένα συγκεκριμένο entry.
- Σελίδα archive ανά ημερολογιακό χρόνο – προβάλει όλους τους μήνες που έχουν καταχωρήσεις για το δοθέντα έτος.
- Σελίδα archive ανά ημερολογιακό μήνα – προβάλει όλες τις μέρες που έχουν καταχωρήσεις για το δοθέντα μήνα.
- Σελίδα archive ανά ημερολογιακή μέρα – προβάλει όλα τα entries μια συγκεκριμένη μέρα.
- Προσθήκη σχολίου – χειρίζεται τα σχόλια πάνω στα posts για ένα συγκεκριμένο entry.

Στη δική μας εφαρμογή, θα έχουμε τα ακόλουθα τέσσερα views:

- Αρχική σελίδα («index») ερωτήσεων – προβάλει τις τελευταίες ερωτήσεις.
- Σελίδα «λεπτομερειών» μιας ερώτησης – προβάλει μια ερώτηση, χωρίς αποτελέσματα, αλλά με μια φόρμα (η οποία θα περιέχει τις επιλογές της ερώτησης) προς ψήφιση.
- Σελίδα «αποτελεσμάτων» μιας ερώτησης – προβάλει τα αποτελέσματα μιας συγκεκριμένης ερώτησης.
- Προσθήκη ψήφου – χειρίζεται τη ψήφο μιας συγκεκριμένης επιλογής μιας συγκεκριμένης ερώτησης.

Στο Django, οι ιστοσελίδες όπως επίσης και άλλα περιεχόμενα εξυπηρετούνται από τα views. Κάθε view αντιπροσωπεύεται από μια απλή Python συνάρτηση (ή μέθοδο, στην περίπτωση των class-based views). Το Django θα διαλέξει το view ανάλογα το URL το οποίο ζητήθηκε (πιο συγκεκριμένα, το μέρος του URL μετά το domain name).

Ίσως μέχρι τώρα έχετε δει στην διαδικτυακή σας περιήγηση μερικές ομορφιές όπως «ME2/Sites/dirmod.asp?sid=&type=gen&mod=Core+Pages&gid=A6CD4967199A42D9B65B1B». Ίσως θα σας χαροποιήσει το γεγονός ότι το Django χρησιμοποιεί (και το κάνει) πολύ πιο κομψά  *URL patterns* εν συγκρίσει με αυτά.

Ένα URL pattern (μοτίβο) είναι απλά μια γενική φόρμα ενός URL – για παράδειγμα: `/newsarchive/<year>/<month>/`.

To get from a URL to a view, Django uses what are known as “URLconfs”. A
URLconf maps URL patterns to views.

This tutorial provides basic instruction in the use of URLconfs, and you can
refer to [URL dispatcher](/el/2.2/topics/http/urls/) for more information.

## Γράφοντας περισσότερα views

Ας προσθέσουμε τώρα μερικά views παραπάνω, στο αρχείο `polls/views.py`. Αυτά τα views είναι ελαφρώς διαφορετικά, επειδή παίρνουν και όρισμα (argument):

*polls/views.py*

```python
def detail(request, question_id):
    return HttpResponse("You're looking at question %s." % question_id)

def results(request, question_id):
    response = "You're looking at the results of question %s."
    return HttpResponse(response % question_id)

def vote(request, question_id):
    return HttpResponse("You're voting on question %s." % question_id)
```

Wire these new views into the `polls.urls` module by adding the following
[`path()`](/el/2.2/ref/urls/#django.urls.path) calls:

*polls/urls.py*

```python
from django.urls import path

from . import views

urlpatterns = [
    # ex: /polls/
    path('', views.index, name='index'),
    # ex: /polls/5/
    path('<int:question_id>/', views.detail, name='detail'),
    # ex: /polls/5/results/
    path('<int:question_id>/results/', views.results, name='results'),
    # ex: /polls/5/vote/
    path('<int:question_id>/vote/', views.vote, name='vote'),
]
```

Ρίξτε μια ματιά με τον browser σας στη σελίδα, «/polls/34/». Με το που πατήσετε enter, το GET request που κάνατε για αυτό το URL θα κάνει trigger το Django project σας, θα γίνει σκανάρισμα των URLs, θα ταιριάξει το δεύτερο URL pattern το οποίο με τη σειρά του θα καλέσει τη μέθοδο `detail()` και η τελευταία θα προβάλει το μήνυμα μαζί με το ID που εισήχθη στο URL (το response το οποίο επιστρέφει η `detail` συνάρτηση). Τώρα δοκιμάστε το «/polls/34/results/» και το «/polls/34/vote/» – αυτά τα URLs θα εμφανίσουν μια σελίδα placeholder για τα αποτελέσματα και τις ψηφοφορίες αντίστοιχα.

When somebody requests a page from your website – say, «/polls/34/», Django
will load the `mysite.urls` Python module because it’s pointed to by the
[`ROOT_URLCONF`](/el/2.2/ref/settings/#std-setting-ROOT_URLCONF) setting. It finds the variable named `urlpatterns`
and traverses the patterns in order. After finding the match at `'polls/'`,
it strips off the matching text (`"polls/"`) and sends the remaining text –
`"34/"` – to the “polls.urls” URLconf for further processing. There it
matches `'<int:question_id>/'`, resulting in a call to the `detail()` view
like so:

```
detail(request=<HttpRequest object>, question_id=34)
```

The `question_id=34` part comes from `<int:question_id>`. Using angle
brackets «captures» part of the URL and sends it as a keyword argument to the
view function. The `:question_id>` part of the string defines the name that
will be used to identify the matched pattern, and the `<int:` part is a
converter that determines what patterns should match this part of the URL path.

There’s no need to add URL cruft such as `.html` – unless you want to, in
which case you can do something like this:

```
path('polls/latest.html', views.index),
```

Αλλά μην το κάνετε. Είναι ανόητο και μη επαγγελματικό.

## Γράφοντας views οι οποίες κάνουν κάτι

Κάθε view είναι υπεύθυνο στο να κάνει ένα από δύο πράγματα: να επιστρέφει ένα [`HttpResponse`](/el/2.2/ref/request-response/#django.http.HttpResponse) object το οποίο περιέχει το περιεχόμενο για την σελίδα που ζητήθηκε ή να κάνει raise κάποιο exception όπως το [`Http404`](/el/2.2/topics/http/views/#django.http.Http404). Τα υπόλοιπα εξαρτώνται από εσάς.

Το view σας μπορεί να διαβάσει records από την βάση δεδομένων ή όχι. Μπορεί να χρησιμοποιήσει ένα template system όπως αυτό του Django – ή κάποιο τρίτο Python template system – ή όχι. Μπορεί να παράγει κάποιο PDF αρχείο, να εξάγει XML, να δημιουργεί κάποιο ZIP αρχείο, να εξάγει JSON δεδομένα, βασικά μπορεί να κάνει τα πάντα χρησιμοποιώντας οποιεσδήποτε βιβλιοθήκες Python επιθυμείτε.

Το μόνο που απαιτείται από το Django είναι ένα [`HttpResponse`](/el/2.2/ref/request-response/#django.http.HttpResponse) ή μια exception.

Επειδή είναι βολικό, θα χρησιμοποιήσουμε το database API του Django, το οποίο καλύψαμε στον [Οδηγό 2](/el/2.2/intro/tutorial02/). Παρακάτω βλέπετε ένα καινούργιο view με το όνομα `index()`, το οποίο εμφανίζει τις τελευταίες 5 ερωτήσεις (που υπάρχουν στην βάση δεδομένων), διαχωρισμένες με κόμμα, βάση της ημερομηνίας που καταχωρήθηκαν (δημιουργήθηκαν):

*polls/views.py*

```python
from django.http import HttpResponse

from .models import Question

def index(request):
    latest_question_list = Question.objects.order_by('-pub_date')[:5]
    output = ', '.join([q.question_text for q in latest_question_list])
    return HttpResponse(output)

# Leave the rest of the views (detail, results, vote) unchanged
```

Υπάρχει ένα πρόβλημα εδώ, όμως: ο σχεδιασμός της σελίδας (design) είναι γραμμένος στο view. Αν χρειαστεί να αλλάξετε τον τρόπο εμφάνιση της σελίδας σας, θα χρειαστεί να επεξεργαστείτε αυτόν τον Python κώδικα. Ας κάνουμε κάτι καλύτερο. Ας χρησιμοποιήσουμε το template system του Django για να διαχωρίσουμε το design από τον Python κώδικα δημιουργώντας ένα template που το view μπορεί να χρησιμοποιήσει.

Για αρχή, δημιουργήστε ένα φάκελο με το όνομα `templates` κάτω από τον φάκελο `polls`. Το Django θα κοιτάξει για templates εκεί.

Η ρύθμιση [`TEMPLATES`](/el/2.2/ref/settings/#std-setting-TEMPLATES) του project σας περιγράφει πως το Django θα φορτώνει και θα κάνει render τα templates. Η προεπιλεγμένη ρύθμιση στο αρχείο settings παραμετροποιεί το `DjangoTemplates` backend του οποίου η ρύθμιση [`APP_DIRS`](/el/2.2/ref/settings/#std-setting-TEMPLATES-APP_DIRS) είναι ρυθμισμένη στο `True`. Έτσι, το `DjangoTemplates` ψάχνει για ένα υπό-φάκελο «templates» σε κάθε εφαρμογή (app) που είναι περασμένη στη ρύθμιση [`INSTALLED_APPS`](/el/2.2/ref/settings/#std-setting-INSTALLED_APPS).

Μέσα στο φάκελο `templates` που μόλις δημιουργήσατε, δημιουργήστε άλλο έναν φάκελο με το όνομα `polls` και μέσα σε αυτό το φάκελο ένα HTML αρχείο με το όνομα `index.html`. Με άλλα λόγια, το template σας θα πρέπει να βρίσκεται στο `polls/templates/polls/index.html`. Λόγω του μηχανισμού λειτουργίας του φορτωτή template (template loader) `app_directories` όπως αναφέρθηκε παραπάνω, μπορείτε να αναφερθείτε σε αυτό το template μέσα στο Django ως `polls/index.html`.

> **Template namespacing**
>
> *Ίσως* θα αναρωτηθήκατε γιατί βάλαμε το template μέσα σε υπό-φάκελο (polls) και όχι μέσα στο φάκελο `polls/templates`. Αν το κάναμε έτσι, τότε δεν θα ήταν και τόσο καλή ιδέα. Το Django θα ψάξει και θα βρει το πρώτο template βάση ονόματος. Αν, λοιπόν, εσείς έχετε ένα άλλο template με το ίδιο όνομα σε μία *διαφορετική* εφαρμογή, τότε το Django δεν θα είναι σε θέση να ξεχωρίσει ποια από τα δύο να χρησιμοποιήσει. Πρέπει καθοδηγήσουμε το Django στην επιλογή του template που θέλουμε και ο ευκολότερος τρόπος είναι να χρησιμοποιήσουμε την τεχνική *namespace*. Αυτό επιτυγχάνεται βάζοντας τα templates μέσα σε έναν *υπό-φάκελο* ο οποίος θα έχει το ίδιο όνομα με το όνομα της εφαρμογής.

Βάλτε τον ακόλουθο κώδικα στο template:

*polls/templates/polls/index.html*

```html+django
{% if latest_question_list %}
    <ul>
    {% for question in latest_question_list %}
        <li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
    {% endfor %}
    </ul>
{% else %}
    <p>No polls are available.</p>
{% endif %}
```

Τώρα, ας ανανεώσουμε το `index` view μέσα στο αρχείο `polls/views.py` ούτως ώστε να χρησιμοποιήσει το νέο μας template:

*polls/views.py*

```python
from django.http import HttpResponse
from django.template import loader

from .models import Question

def index(request):
    latest_question_list = Question.objects.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))
```

Αυτός ο κώδικας φορτώνει το template με το όνομα `polls/index.html` και περνάει σε αυτό ένα context. Το context είναι ένα dictionary το οποίο αντιστοιχεί template variable ονόματα σε Python objects.

Πηγαίνετε στη σελίδα με το browser σας στο «/polls/» και θα πρέπει να δείτε μια λίστα (με κουκίδες) η οποία περιέχει την ερώτηση «What’s up» που φτιάξαμε στον [Οδηγό 2](/el/2.2/intro/tutorial02/). Το link δείχνει στην σελίδα με τις λεπτομέρειες της ερώτησης.

### Η συντόμευση: [`render()`](/el/2.2/topics/http/shortcuts/#django.shortcuts.render)

Είναι πολύ συνηθισμένο να φορτώνεται ένα template, να γεμίζεται ένα context και να επιστρέφεται ένα
[`HttpResponse`](/el/2.2/ref/request-response/#django.http.HttpResponse) object του οποίου το αποτέλεσμα θα είναι το rendered template. Το Django παρέχει μια συντόμευση για όλα αυτά. Ορίστε πάλι το `index()` view, γραμμένο από την αρχή:

*polls/views.py*

```python
from django.shortcuts import render

from .models import Question

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

Σημειώστε ότι, αφού χρησιμοποιήσουμε την [`render()`](/el/2.2/topics/http/shortcuts/#django.shortcuts.render) για *όλες* τις views, δεν χρειάζεται πλέον να κάνουμε import τα [`loader`](/el/2.2/topics/templates/#module-django.template.loader) και [`HttpResponse`](/el/2.2/ref/request-response/#django.http.HttpResponse). Παραταύτα, θα χρειαστεί να κρατήσετε το `HttpResponse` αν έχετε ακόμη τις μεθόδους  για το\`\`detail\`\`, `results` και `vote` view.

Η συνάρτηση [`render()`](/el/2.2/topics/http/shortcuts/#django.shortcuts.render) παίρνει ως πρώτο όρισμα το request object, ως δεύτερο το όνομα του template και ένα dictionary ως τρίτο προαιρετικό. Επιστρέφει ένα [`HttpResponse`](/el/2.2/ref/request-response/#django.http.HttpResponse) object του δηλωθέν template το οποίο template έχει γίνει rendered βάση του δοθέν context.

## Raising σφάλμα 404

Σε αυτό το σημείο θα πειράξουμε το view που αφορά στις λεπτομέρειες μιας ερώτησης – τη σελίδα, δηλαδή, η οποία εμφανίζει την ερώτηση για μια συγκεκριμένη ψηφοφορία. Αυτό είναι το view:

*polls/views.py*

```python
from django.http import Http404
from django.shortcuts import render

from .models import Question
# ...
def detail(request, question_id):
    try:
        question = Question.objects.get(pk=question_id)
    except Question.DoesNotExist:
        raise Http404("Question does not exist")
    return render(request, 'polls/detail.html', {'question': question})
```

Το νέο concept εδώ είναι: Το view κάνει raise την exception [`Http404`](/el/2.2/topics/http/views/#django.http.Http404) αν η ερώτηση με το συγκεκριμένο ID δεν υπάρχει (στη βάση δεδομένων).

Θα συζητήσουμε τι μπορείτε να βάλετε μέσα στο template με το όνομα `polls/detail.html` λίγο αργότερα, αλλά τώρα αν βιάζεστε να δείτε πως θα φαίνεται γράψτε τα ακόλουθα στο αρχείο `polls/detail.html`:

*polls/templates/polls/detail.html*

```html+django
{{ question }}
```

Αυτό θα σας δώσει μια ιδέα.

### Η συντόμευση: [`get_object_or_404()`](/el/2.2/topics/http/shortcuts/#django.shortcuts.get_object_or_404)

Είναι συνηθισμένο να χρησιμοποιείται η μέθοδος [`get()`](/el/2.2/ref/models/querysets/#django.db.models.query.QuerySet.get) η οποία να κάνει raise το exception [`Http404`](/el/2.2/topics/http/views/#django.http.Http404) αν το object δεν υπάρχει. Το Django σας παρέχει μια συντόμευση και γι’ αυτό. Παρακάτω φαίνεται το `detail()` view, γραμμένο από την αρχή (πάλι):

*polls/views.py*

```python
from django.shortcuts import get_object_or_404, render

from .models import Question
# ...
def detail(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    return render(request, 'polls/detail.html', {'question': question})
```

Η συνάρτηση [`get_object_or_404()`](/el/2.2/topics/http/shortcuts/#django.shortcuts.get_object_or_404) παίρνει ως πρώτο όρισμα ένα Django model και ένα αυθαίρετο αριθμό από arguments, τα οποία τα δίνει στην μέθοδο [`get()`](/el/2.2/ref/models/querysets/#django.db.models.query.QuerySet.get) του manager του μοντέλου (model manager) που περάστηκε  ως πρώτο όρισμα. Η συνάρτηση αυτή κάνει raise το exception [`Http404`](/el/2.2/topics/http/views/#django.http.Http404) αν το object δεν υπάρχει.

> **Φιλοσοφία**
>
> Γιατί όμως χρησιμοποιούμε την βοηθητική συνάρτηση (helper function) [`get_object_or_404()`](/el/2.2/topics/http/shortcuts/#django.shortcuts.get_object_or_404) αντί να κάνουμε αυτόματα το catch του exception [`ObjectDoesNotExist`](/el/2.2/ref/exceptions/#django.core.exceptions.ObjectDoesNotExist) σε ένα υψηλότερο επίπεδο; Επίσης, γιατί να βάλουμε το model API να κάνει raise το exception [`Http404`](/el/2.2/topics/http/views/#django.http.Http404) αντί του exception [`ObjectDoesNotExist`](/el/2.2/ref/exceptions/#django.core.exceptions.ObjectDoesNotExist);
>
> Η απάντηση είναι ίδια και στις δύο ερωτήσεις. Επειδή αυτό θα δεσμεύσει το επίπεδο του model με το επίπεδο του view. Ένας από τους πρωταρχικούς στόχους του Django είναι να διατηρηθεί η ανεξαρτητοποίηση και η μη σύνδεση μεταξύ οντοτήτων (το λεγόμενο loose coupling). Μερικά ελεγχόμενα couplings παρουσιάζονται στο module [`django.shortcuts`](/el/2.2/topics/http/shortcuts/#module-django.shortcuts).

Υπάρχει επίσης η συνάρτηση [`get_list_or_404()`](/el/2.2/topics/http/shortcuts/#django.shortcuts.get_list_or_404), η οποία λειτουργεί πανομοιότυπα με την [`get_object_or_404()`](/el/2.2/topics/http/shortcuts/#django.shortcuts.get_object_or_404) – με τη μόνη διαφορά ότι χρησιμοποιεί την μέθοδο [`filter()`](/el/2.2/ref/models/querysets/#django.db.models.query.QuerySet.filter) αντί της [`get()`](/el/2.2/ref/models/querysets/#django.db.models.query.QuerySet.get). Η [`get_list_or_404()`](/el/2.2/topics/http/shortcuts/#django.shortcuts.get_list_or_404) κάνει raise την exception [`Http404`](/el/2.2/topics/http/views/#django.http.Http404) αν η λίστα είναι κενή (άδεια).

## Χρησιμοποιώντας ένα template system

Πίσω στο `detail()` view της εφαρμογής μας. Έχοντας το context variable με το όνομα `question`, το template `polls/detail.html` θα δείχνει κάπως έτσι:

*polls/templates/polls/detail.html*

```html+django
<h1>{{ question.question_text }}</h1>
<ul>
{% for choice in question.choice_set.all %}
    <li>{{ choice.choice_text }}</li>
{% endfor %}
</ul>
```

Το template system χρησιμοποιεί την σύνταξη της τελείας για να ψάχνει μέσα στα variable attributes. Στο παράδειγμα του `{{ question.question_text }}`, το Django θα ψάξει πρώτα μέσα στο dictionary του object `question`. Αν δεν βρει τίποτα (δεν υπάρχει, δηλαδή, το key ```question_text``στο υποτιθέμενο dictionary), προσπαθεί να βρει το ``question_text``` σαν attribute του object – το οποίο στη συγκεκριμένη περίπτωση ισχύει. Αν όμως δεν υπήρχε, τότε θα έψαχνε σε μια λίστα να το βρει.

Ο τρόπος για να καλείτε μεθόδους φαίνεται στο βρόγχο επανάληψης [`{% for %}`](/el/2.2/ref/templates/builtins/#std-templatetag-for):  το `question.choice_set.all` μεταφράζεται ως Python κώδικας `question.choice_set.all()`, το οποίο επιστρέφει ένα iterable από `Choice` objects και είναι βολικό προς χρήση (στην παρούσα) με τον βρόγχο επανάληψης [`{% for %}`](/el/2.2/ref/templates/builtins/#std-templatetag-for) (το οποίο αναφέρεται και ως `template tag`).

Δείτε το άρθρο [templates](/el/2.2/topics/templates/) για περισσότερα σχετικά με τα templates.

## Αφαίρεση των hardcoded URLs στα templates

Θυμηθείτε ότι πριν, δηλώσαμε στην HTML το link για την ερώτηση στο template `polls/index.html` ως:

```html+django
<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
```

The problem with this hardcoded, tightly-coupled approach is that it becomes
challenging to change URLs on projects with a lot of templates. However, since
you defined the name argument in the [`path()`](/el/2.2/ref/urls/#django.urls.path) functions in
the `polls.urls` module, you can remove a reliance on specific URL paths
defined in your url configurations by using the `{% url %}` template tag:

```html+django
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
```

Ο τρόπος με τον οποίο λειτουργεί αυτό το template tag είναι κοιτώντας τα URLs που έχετε ορίσει στο module `polls.urls`. Μπορείτε να δείτε ακριβώς σε ποιο URL έχει οριστεί το όνομα “detail” παρακάτω:

```
...
# the 'name' value as called by the {% url %} template tag
path('<int:question_id>/', views.detail, name='detail'),
...
```

Αν θέλετε να αλλάξετε το URL αυτού του view σε κάτι άλλο (ίσως στο `polls/specifics/12/`), τότε αντί να ψάχνετε όλα τα templates που είχατε δηλώσει το παλιό URL προκειμένου να το αντικαταστήσετε με το καινούργιο, πολύ απλά πειράζετε ένα αρχείο (`polls/urls.py`) και όλα τα υπόλοιπα ανανεώνονται αυτόματα, χάρη στο template tag `{% url %}`:

```
...
# added the word 'specifics'
path('specifics/<int:question_id>/', views.detail, name='detail'),
...
```

## Χρησιμοποιώντας namespacing στα ονόματα των URL

Το project του οδηγού αυτού έχει μόνο μια εφαρμογή, την `polls`. Σε πραγματικά Django projects, ίσως να έχετε πέντε, δέκα, είκοσι ή περισσότερα apps. Πως μπορεί να ξέρει και να διαφοροποιεί το Django τα ονόματα των URLs ανάμεσα σε τόσα apps; Για παράδειγμα, η εφαρμογή `polls` έχει ένα `detail` view και ίσως ένα άλλο app (στο ίδιο project) να έχει το ίδιο όνομα για ένα δικό του view. Όταν το Django συναντήσει το template tag `{% url 'detail' %}` πως θα ξέρει σε ποιο view να αναφερθεί;

Η απάντηση έρχεται με την προσθήκη namespaces στο URLconf. Στο αρχείο `polls/urls.py`, προσθέστε μια μεταβλητή `app_name` ούτως ώστε να θέσετε το namespace για αυτό το app:

*polls/urls.py*

```python
from django.urls import path

from . import views

app_name = 'polls'
urlpatterns = [
    path('', views.index, name='index'),
    path('<int:question_id>/', views.detail, name='detail'),
    path('<int:question_id>/results/', views.results, name='results'),
    path('<int:question_id>/vote/', views.vote, name='vote'),
]
```

Τώρα, πηγαίνετε και αλλάξτε το αρχείο polls/index.html\`\`από:

*polls/templates/polls/index.html*

```html+django
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
```

στο:

*polls/templates/polls/index.html*

```html+django
<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>
```

Όταν αισθανθείτε άνετα με τη συγγραφή των views, διαβάστε το [τέταρτο μέρος αυτού του οδηγού](/el/2.2/intro/tutorial04/) για να μάθετε το πώς να διαχειρίζεστε απλές φόρμες και τα Django generic views.
