{"title":"Γράφοντας το πρώτο σας Django app, μέρος 4","version":"3.1","locale":"el","docname":"intro/tutorial04","url":"/el/3.1/intro/tutorial04/","canonical":"https://djangodocs.dev/el/3.1/intro/tutorial04/","summary":"This tutorial begins where Tutorial 3 left off. We’re continuing the Web-poll application and will focus on form processing and cutting down our code. Που να ψάξετε…","html":"<h1>Γράφοντας το πρώτο σας Django app, μέρος 4<a class=\"heading-anchor\" href=\"#writing-your-first-django-app-part-4\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h1>\n<p>This tutorial begins where <a class=\"reference internal\" href=\"/el/3.1/intro/tutorial03/\"><span class=\"doc\">Tutorial 3</span></a> left off. We’re\ncontinuing the Web-poll application and will focus on form processing and\ncutting down our code.</p>\n<aside class=\"admonition-where-to-get-help admonition\">\n<p class=\"admonition-title\">Που να ψάξετε για βοήθεια</p>\n<p>If you’re having trouble going through this tutorial, please head over to\nthe <a class=\"reference internal\" href=\"/el/3.1/faq/help/\"><span class=\"doc\">Getting Help</span></a> section of the FAQ.</p>\n</aside>\n<section id=\"write-a-minimal-form\">\n<h2>Write a minimal form<a class=\"heading-anchor\" href=\"#write-a-minimal-form\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Ας αναβαθμίσουμε το HTML template («polls/detail.html»), από τον προηγούμενο οδηγό, στο οποίο εμφανίζουμε τις λεπτομέρειες της ψηφοφορίας. Αυτή τη φορά θα προσθέσουμε ένα HTML <code class=\"docutils literal notranslate\"><span class=\"pre\">&lt;form&gt;</span></code> element:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"html+django\"><figcaption class=\"code-block-caption\">polls/templates/polls/detail.html</figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Django template</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Django template code\"><code><span class=\"p\">&lt;</span><span class=\"nt\">h1</span><span class=\"p\">&gt;</span><span class=\"cp\">{{</span> <span class=\"nv\">question.question_text</span> <span class=\"cp\">}}</span><span class=\"p\">&lt;/</span><span class=\"nt\">h1</span><span class=\"p\">&gt;</span>\n\n<span class=\"cp\">{%</span> <span class=\"k\">if</span> <span class=\"nv\">error_message</span> <span class=\"cp\">%}</span><span class=\"p\">&lt;</span><span class=\"nt\">p</span><span class=\"p\">&gt;&lt;</span><span class=\"nt\">strong</span><span class=\"p\">&gt;</span><span class=\"cp\">{{</span> <span class=\"nv\">error_message</span> <span class=\"cp\">}}</span><span class=\"p\">&lt;/</span><span class=\"nt\">strong</span><span class=\"p\">&gt;&lt;/</span><span class=\"nt\">p</span><span class=\"p\">&gt;</span><span class=\"cp\">{%</span> <span class=\"k\">endif</span> <span class=\"cp\">%}</span>\n\n<span class=\"p\">&lt;</span><span class=\"nt\">form</span> <span class=\"na\">action</span><span class=\"o\">=</span><span class=\"s\">&quot;</span><span class=\"cp\">{%</span> <span class=\"k\">url</span> <span class=\"s1\">&#39;polls:vote&#39;</span> <span class=\"nv\">question.id</span> <span class=\"cp\">%}</span><span class=\"s\">&quot;</span> <span class=\"na\">method</span><span class=\"o\">=</span><span class=\"s\">&quot;post&quot;</span><span class=\"p\">&gt;</span>\n<span class=\"cp\">{%</span> <span class=\"k\">csrf_token</span> <span class=\"cp\">%}</span>\n<span class=\"cp\">{%</span> <span class=\"k\">for</span> <span class=\"nv\">choice</span> <span class=\"k\">in</span> <span class=\"nv\">question.choice_set.all</span> <span class=\"cp\">%}</span>\n    <span class=\"p\">&lt;</span><span class=\"nt\">input</span> <span class=\"na\">type</span><span class=\"o\">=</span><span class=\"s\">&quot;radio&quot;</span> <span class=\"na\">name</span><span class=\"o\">=</span><span class=\"s\">&quot;choice&quot;</span> <span class=\"na\">id</span><span class=\"o\">=</span><span class=\"s\">&quot;choice</span><span class=\"cp\">{{</span> <span class=\"nb\">forloop</span><span class=\"nv\">.counter</span> <span class=\"cp\">}}</span><span class=\"s\">&quot;</span> <span class=\"na\">value</span><span class=\"o\">=</span><span class=\"s\">&quot;</span><span class=\"cp\">{{</span> <span class=\"nv\">choice.id</span> <span class=\"cp\">}}</span><span class=\"s\">&quot;</span><span class=\"p\">&gt;</span>\n    <span class=\"p\">&lt;</span><span class=\"nt\">label</span> <span class=\"na\">for</span><span class=\"o\">=</span><span class=\"s\">&quot;choice</span><span class=\"cp\">{{</span> <span class=\"nb\">forloop</span><span class=\"nv\">.counter</span> <span class=\"cp\">}}</span><span class=\"s\">&quot;</span><span class=\"p\">&gt;</span><span class=\"cp\">{{</span> <span class=\"nv\">choice.choice_text</span> <span class=\"cp\">}}</span><span class=\"p\">&lt;/</span><span class=\"nt\">label</span><span class=\"p\">&gt;&lt;</span><span class=\"nt\">br</span><span class=\"p\">&gt;</span>\n<span class=\"cp\">{%</span> <span class=\"k\">endfor</span> <span class=\"cp\">%}</span>\n<span class=\"p\">&lt;</span><span class=\"nt\">input</span> <span class=\"na\">type</span><span class=\"o\">=</span><span class=\"s\">&quot;submit&quot;</span> <span class=\"na\">value</span><span class=\"o\">=</span><span class=\"s\">&quot;Vote&quot;</span><span class=\"p\">&gt;</span>\n<span class=\"p\">&lt;/</span><span class=\"nt\">form</span><span class=\"p\">&gt;</span>\n</code></pre></figure>\n<p>Εδώ συμβαίνουν τα εξής:</p>\n<ul class=\"simple\">\n<li><p>Το παραπάνω template εμφανίζει ένα radio button για κάθε επιλογή ερώτησης. Η τιμή (<code class=\"docutils literal notranslate\"><span class=\"pre\">value</span></code>) κάθε radio button είναι το ID αυτού. Το όνομα (<code class=\"docutils literal notranslate\"><span class=\"pre\">name</span></code>) σε όλα τα radio buttons είναι <code class=\"docutils literal notranslate\"><span class=\"pre\">&quot;choice&quot;</span></code>. Αυτό σημαίνει ότι, όταν κάποιος επιλέγει κάποια από τις πιθανές απαντήσεις και κάνει submit τη φόρμα, τότε θα σταλούν (στον server) τα εξής δεδομένα με τη μέθοδο POST (POST data): <code class=\"docutils literal notranslate\"><span class=\"pre\">choice=#</span></code> όπου # είναι το ID της επιλεγμένης απάντησης (στέλνεται, δηλαδή, το name του input μαζί με το value του ίδιου σε μια μορφή key=value). Αυτό είναι το βασικό concept των HTML forms.</p></li>\n<li><p>We set the form’s <code class=\"docutils literal notranslate\"><span class=\"pre\">action</span></code> to <code class=\"docutils literal notranslate\"><span class=\"pre\">{%</span> <span class=\"pre\">url</span> <span class=\"pre\">'polls:vote'</span> <span class=\"pre\">question.id</span> <span class=\"pre\">%}</span></code>, and we\nset <code class=\"docutils literal notranslate\"><span class=\"pre\">method=&quot;post&quot;</span></code>. Using <code class=\"docutils literal notranslate\"><span class=\"pre\">method=&quot;post&quot;</span></code> (as opposed to\n<code class=\"docutils literal notranslate\"><span class=\"pre\">method=&quot;get&quot;</span></code>) is very important, because the act of submitting this\nform will alter data server-side. Whenever you create a form that alters\ndata server-side, use <code class=\"docutils literal notranslate\"><span class=\"pre\">method=&quot;post&quot;</span></code>. This tip isn’t specific to\nDjango; it’s good Web development practice in general.</p></li>\n<li><p>Το <code class=\"docutils literal notranslate\"><span class=\"pre\">forloop.counter</span></code> δείχνει τον αριθμό που ο βρόγχος επανάληψης <a class=\"reference internal\" href=\"/el/3.1/ref/templates/builtins/#std-templatetag-for\"><code class=\"xref std std-ttag docutils literal notranslate\"><span class=\"pre\">for</span></code></a> έχει τρέξει. Αυτό το κάνουμε για να λάβει κάθε <code class=\"docutils literal notranslate\"><span class=\"pre\">input</span></code> element μοναδικό id.</p></li>\n<li><p>Since we’re creating a POST form (which can have the effect of modifying\ndata), we need to worry about Cross Site Request Forgeries.\nThankfully, you don’t have to worry too hard, because Django comes with a\nhelpful system for protecting against it. In short, all POST forms that are\ntargeted at internal URLs should use the <a class=\"reference internal\" href=\"/el/3.1/ref/templates/builtins/#std-templatetag-csrf_token\"><code class=\"xref std std-ttag docutils literal notranslate\"><span class=\"pre\">{%</span> <span class=\"pre\">csrf_token</span> <span class=\"pre\">%}</span></code></a>\ntemplate tag.</p></li>\n</ul>\n<p>Ας δημιουργήσουμε τώρα ένα Django view το οποίο θα χειριστεί τα δεδομένα τα οποία έγιναν submit από τη φόρμα. Θυμηθείτε ότι στον <a class=\"reference internal\" href=\"/el/3.1/intro/tutorial03/\"><span class=\"doc\">Οδηγό 3</span></a>, δημιουργήσαμε ένα URLconf, το οποίο περιλαμβάνει τη γραμμή:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\">polls/urls.py</figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"n\">path</span><span class=\"p\">(</span><span class=\"s1\">&#39;&lt;int:question_id&gt;/vote/&#39;</span><span class=\"p\">,</span> <span class=\"n\">views</span><span class=\"o\">.</span><span class=\"n\">vote</span><span class=\"p\">,</span> <span class=\"n\">name</span><span class=\"o\">=</span><span class=\"s1\">&#39;vote&#39;</span><span class=\"p\">),</span>\n</code></pre></figure>\n<p>Δημιουργήσαμε επίσης μια πρόχειρη υλοποίηση της συνάρτησης (view) <code class=\"docutils literal notranslate\"><span class=\"pre\">vote()</span></code>. Ας αναβαθμίσουμε και αυτό το view για να χειριστεί τα data. Προσθέστε τα ακόλουθα στο αρχείο <code class=\"docutils literal notranslate\"><span class=\"pre\">polls/views.py</span></code>:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\">polls/views.py</figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.http</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">HttpResponse</span><span class=\"p\">,</span> <span class=\"n\">HttpResponseRedirect</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.shortcuts</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">get_object_or_404</span><span class=\"p\">,</span> <span class=\"n\">render</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.urls</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">reverse</span>\n\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">Choice</span><span class=\"p\">,</span> <span class=\"n\">Question</span>\n<span class=\"c1\"># ...</span>\n<span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">vote</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">,</span> <span class=\"n\">question_id</span><span class=\"p\">):</span>\n    <span class=\"n\">question</span> <span class=\"o\">=</span> <span class=\"n\">get_object_or_404</span><span class=\"p\">(</span><span class=\"n\">Question</span><span class=\"p\">,</span> <span class=\"n\">pk</span><span class=\"o\">=</span><span class=\"n\">question_id</span><span class=\"p\">)</span>\n    <span class=\"k\">try</span><span class=\"p\">:</span>\n        <span class=\"n\">selected_choice</span> <span class=\"o\">=</span> <span class=\"n\">question</span><span class=\"o\">.</span><span class=\"n\">choice_set</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">pk</span><span class=\"o\">=</span><span class=\"n\">request</span><span class=\"o\">.</span><span class=\"n\">POST</span><span class=\"p\">[</span><span class=\"s1\">&#39;choice&#39;</span><span class=\"p\">])</span>\n    <span class=\"k\">except</span> <span class=\"p\">(</span><span class=\"ne\">KeyError</span><span class=\"p\">,</span> <span class=\"n\">Choice</span><span class=\"o\">.</span><span class=\"n\">DoesNotExist</span><span class=\"p\">):</span>\n        <span class=\"c1\"># Redisplay the question voting form.</span>\n        <span class=\"k\">return</span> <span class=\"n\">render</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">,</span> <span class=\"s1\">&#39;polls/detail.html&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span>\n            <span class=\"s1\">&#39;question&#39;</span><span class=\"p\">:</span> <span class=\"n\">question</span><span class=\"p\">,</span>\n            <span class=\"s1\">&#39;error_message&#39;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;You didn&#39;t select a choice.&quot;</span><span class=\"p\">,</span>\n        <span class=\"p\">})</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">selected_choice</span><span class=\"o\">.</span><span class=\"n\">votes</span> <span class=\"o\">+=</span> <span class=\"mi\">1</span>\n        <span class=\"n\">selected_choice</span><span class=\"o\">.</span><span class=\"n\">save</span><span class=\"p\">()</span>\n        <span class=\"c1\"># Always return an HttpResponseRedirect after successfully dealing</span>\n        <span class=\"c1\"># with POST data. This prevents data from being posted twice if a</span>\n        <span class=\"c1\"># user hits the Back button.</span>\n        <span class=\"k\">return</span> <span class=\"n\">HttpResponseRedirect</span><span class=\"p\">(</span><span class=\"n\">reverse</span><span class=\"p\">(</span><span class=\"s1\">&#39;polls:results&#39;</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"o\">=</span><span class=\"p\">(</span><span class=\"n\">question</span><span class=\"o\">.</span><span class=\"n\">id</span><span class=\"p\">,)))</span>\n</code></pre></figure>\n<p>Ο παραπάνω κώδικας περιλαμβάνει μερικά πράγματα τα οποία δεν έχουμε καλύψει μέχρι τώρα στον οδηγό:</p>\n<ul>\n<li><p>Το object <a class=\"reference internal\" href=\"/el/3.1/ref/request-response/#django.http.HttpRequest.POST\" title=\"django.http.HttpRequest.POST\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">request.POST</span></code></a> έχει τη μορφή ενός dictionary το οποίο σας επιτρέπει να έχετε πρόσβαση στα submitted data μέσω του ονόματος του key (όπως ακριβώς λειτουργεί ένα dictionary στην Python). Στην περίπτωση μας, το <code class=\"docutils literal notranslate\"><span class=\"pre\">request.POST['choice']</span></code> επιστρέφει το ID της επιλεγμένης απάντησης, υπό τη μορφή ενός string. Όλες οι τιμές μέσα το object <a class=\"reference internal\" href=\"/el/3.1/ref/request-response/#django.http.HttpRequest.POST\" title=\"django.http.HttpRequest.POST\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">request.POST</span></code></a> έχουν τη μορφή string.</p>\n<p>Σημειώστε ότι το Django παρέχει επίσης ανάλογη πρόσβαση στα GET data (αν χρησιμοποιηθεί το <code class=\"docutils literal notranslate\"><span class=\"pre\">method=&quot;get&quot;</span></code>) μέσω του object <a class=\"reference internal\" href=\"/el/3.1/ref/request-response/#django.http.HttpRequest.GET\" title=\"django.http.HttpRequest.GET\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">request.GET</span></code></a> – αλλά στο συγκεκριμένο παράδειγμα χρησιμοποιούμε αποκλειστικά την <a class=\"reference internal\" href=\"/el/3.1/ref/request-response/#django.http.HttpRequest.POST\" title=\"django.http.HttpRequest.POST\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">request.POST</span></code></a>, για να σιγουρευτούμε ότι τα data θα αλλάξουν (στη βάση δεδομένων) μόνο από κάποιο POST call (και ότι τυχόν από κάπου αλλού).</p>\n</li>\n<li><p>Το object <code class=\"docutils literal notranslate\"><span class=\"pre\">request.POST['choice']</span></code> θα κάνει raise το exception <a class=\"reference external\" href=\"https://docs.python.org/3/library/exceptions.html#KeyError\" title=\"(στη Python έκδοση 3.14)\"><code class=\"xref py py-exc docutils literal notranslate\"><span class=\"pre\">KeyError</span></code></a> (όπως και ένα κοινό Python dictionary) αν το key <code class=\"docutils literal notranslate\"><span class=\"pre\">choice</span></code> δεν βρεθεί (δεν υπάρχει, δηλαδή, στα POST data). Ο παραπάνω κώδικας κάνει handle το exception αυτό με το να επανεμφανίσει τη φόρμα ψηφοφορίας με ένα ανάλογο μήνυμα σφάλματος (error message).</p></li>\n<li><p>Αφού αυξήσουμε το πλήθος των ψήφων (κατά ένα, κάθε φορά), ο κώδικας επιστρέφει ένα object <a class=\"reference internal\" href=\"/el/3.1/ref/request-response/#django.http.HttpResponseRedirect\" title=\"django.http.HttpResponseRedirect\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">HttpResponseRedirect</span></code></a> παρά ένα συνηθισμένο <a class=\"reference internal\" href=\"/el/3.1/ref/request-response/#django.http.HttpResponse\" title=\"django.http.HttpResponse\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">HttpResponse</span></code></a>. Το object <a class=\"reference internal\" href=\"/el/3.1/ref/request-response/#django.http.HttpResponseRedirect\" title=\"django.http.HttpResponseRedirect\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">HttpResponseRedirect</span></code></a> αρχικοποιείται (initializes) με ένα όρισμα (argument): το URL στο οποίο θα ανακατευθυνθεί ο χρήστης (δείτε τις ακόλουθες δύο παραγράφους σχετικά με το πως χτίζουμε το URL σε αυτή την περίπτωση).</p>\n<p>As the Python comment above points out, you should always return an\n<a class=\"reference internal\" href=\"/el/3.1/ref/request-response/#django.http.HttpResponseRedirect\" title=\"django.http.HttpResponseRedirect\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">HttpResponseRedirect</span></code></a> after successfully dealing with\nPOST data. This tip isn’t specific to Django; it’s good Web development\npractice in general.</p>\n</li>\n<li><p>Χρησιμοποιούμε τη συνάρτηση <a class=\"reference internal\" href=\"/el/3.1/ref/urlresolvers/#django.urls.reverse\" title=\"django.urls.reverse\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">reverse()</span></code></a> στον constructor της κλάσης <a class=\"reference internal\" href=\"/el/3.1/ref/request-response/#django.http.HttpResponseRedirect\" title=\"django.http.HttpResponseRedirect\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">HttpResponseRedirect</span></code></a>. Η συνάρτηση αυτή βοηθά στο να αποφύγουμε να γράφουμε ολόκληρα τα URLs (hardcode) μέσα στη συνάρτηση view (ή οπουδήποτε αλλού σε Python κώδικα). Σαν ορίσματα παίρνει το όνομα του URL (π.χ αυτό που έχουμε ορίσει ως name μέσα στη συνάρτηση <code class=\"docutils literal notranslate\"><span class=\"pre\">url()</span></code> στο αρχείο <code class=\"docutils literal notranslate\"><span class=\"pre\">polls/urls.py</span></code>, με πρόθεμα το όνομα του application για τυχόν namespacing) και τυχόν arguments (είτε positional είτε named) τα οποία έχουν περαστεί μέσα στο URL  (αυτά που “αιχμαλωτίστηκαν” λόγω των regular expressions). Στη δικιά μας περίπτωση, χρησιμοποιώντας το URLconf που δημιουργήσαμε στον <a class=\"reference internal\" href=\"/el/3.1/intro/tutorial03/\"><span class=\"doc\">Οδηγό 3</span></a>, η κλήση της συνάρτησης <a class=\"reference internal\" href=\"/el/3.1/ref/urlresolvers/#django.urls.reverse\" title=\"django.urls.reverse\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">reverse()</span></code></a> θα επιστρέψει ένα string όπως το παρακάτω:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"s1\">&#39;/polls/3/results/&#39;</span>\n</code></pre></div>\n<p>όπου <code class=\"docutils literal notranslate\"><span class=\"pre\">3</span></code> είναι η τιμή του <code class=\"docutils literal notranslate\"><span class=\"pre\">question.id</span></code>. Αυτό το URL θα καλέσει το view με το όνομα <code class=\"docutils literal notranslate\"><span class=\"pre\">'results'</span></code> για να εμφανίσει τη σελίδα (το rendered template, δηλαδή, <code class=\"docutils literal notranslate\"><span class=\"pre\">polls/detail.html</span></code>). Όταν λέμε rendered template ας εξηγήσουμε τι εννοούμε. Είναι πολύ απλό. Μέσα σε ένα template (συνήθως μια HTML σελίδα), συνήθως βάζουμε περιεχόμενο το οποίο αναμένουμε να “γεμίσει” με μια τιμή από κάπου (συνήθως από το view που κάλεσε αυτό το template). Είδαμε κάτι τέτοιο στον <a class=\"reference internal\" href=\"/el/3.1/intro/tutorial03/\"><span class=\"doc\">Οδηγό 3</span></a> όπου στο template <code class=\"docutils literal notranslate\"><span class=\"pre\">polls/detail.html</span></code> βάλαμε την έκφραση {{ choice.choice_text }} μέσα σε ένα <code class=\"docutils literal notranslate\"><span class=\"pre\">&lt;li&gt;&lt;/li&gt;</span></code> HTML element. Αυτή η τιμή θα “γεμίσει” από το context που θα περάσει το view στο template (μέσω της <code class=\"docutils literal notranslate\"><span class=\"pre\">render()</span></code> φυσικά). Το context δεν είναι τίποτε άλλο παρά ένα dictionary όπου τα keys ονομάζονται context variables. Υπολογίστηκαν κάποιες τιμές στο view και με κάποιον τρόπο θα πρέπει να περαστούν στο template. Όταν το template γεμίσει με τις απαραίτητες τιμές τότε έχει γίνει rendered.</p>\n</li>\n</ul>\n<p>Όπως αναφέρθηκε στον <a class=\"reference internal\" href=\"/el/3.1/intro/tutorial03/\"><span class=\"doc\">Οδηγό 3</span></a>, το <code class=\"docutils literal notranslate\"><span class=\"pre\">request</span></code> είναι ένα object της κλάσης <a class=\"reference internal\" href=\"/el/3.1/ref/request-response/#django.http.HttpRequest\" title=\"django.http.HttpRequest\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">HttpRequest</span></code></a>. Για περισσότερες πληροφορίες σχετικά με τα objects της κλάσης <a class=\"reference internal\" href=\"/el/3.1/ref/request-response/#django.http.HttpRequest\" title=\"django.http.HttpRequest\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">HttpRequest</span></code></a>, δείτε το άρθρο <a class=\"reference internal\" href=\"/el/3.1/ref/request-response/\"><span class=\"doc\">εγχειρίδιο του request και response</span></a>.</p>\n<p>Όταν κάποιος ψηφίσει στην ερώτηση, τότε το view <code class=\"docutils literal notranslate\"><span class=\"pre\">vote()</span></code> θα ανακατευθύνει το χρήστη στη σελίδα των αποτελεσμάτων για αυτή την ερώτηση. Ας γράψουμε αυτό το view:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\">polls/views.py</figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.shortcuts</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">get_object_or_404</span><span class=\"p\">,</span> <span class=\"n\">render</span>\n\n\n<span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">results</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">,</span> <span class=\"n\">question_id</span><span class=\"p\">):</span>\n    <span class=\"n\">question</span> <span class=\"o\">=</span> <span class=\"n\">get_object_or_404</span><span class=\"p\">(</span><span class=\"n\">Question</span><span class=\"p\">,</span> <span class=\"n\">pk</span><span class=\"o\">=</span><span class=\"n\">question_id</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">render</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">,</span> <span class=\"s1\">&#39;polls/results.html&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;question&#39;</span><span class=\"p\">:</span> <span class=\"n\">question</span><span class=\"p\">})</span>\n</code></pre></figure>\n<p>Αυτό το view είναι σχεδόν πανομοιότυπο με το <code class=\"docutils literal notranslate\"><span class=\"pre\">detail()</span></code> από τον <a class=\"reference internal\" href=\"/el/3.1/intro/tutorial03/\"><span class=\"doc\">Οδηγό 3</span></a>. Η μόνη διαφορά είναι το όνομα του template. Θα φτιάξουμε αυτό τον πλεονασμό αργότερα. Μας αρέσει να ακολουθάμε την τακτική DRY (don’t repeat yourself).</p>\n<p>Τώρα, δημιουργήστε το template με το όνομα <code class=\"docutils literal notranslate\"><span class=\"pre\">polls/results.html</span></code>:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"html+django\"><figcaption class=\"code-block-caption\">polls/templates/polls/results.html</figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Django template</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Django template code\"><code><span class=\"p\">&lt;</span><span class=\"nt\">h1</span><span class=\"p\">&gt;</span><span class=\"cp\">{{</span> <span class=\"nv\">question.question_text</span> <span class=\"cp\">}}</span><span class=\"p\">&lt;/</span><span class=\"nt\">h1</span><span class=\"p\">&gt;</span>\n\n<span class=\"p\">&lt;</span><span class=\"nt\">ul</span><span class=\"p\">&gt;</span>\n<span class=\"cp\">{%</span> <span class=\"k\">for</span> <span class=\"nv\">choice</span> <span class=\"k\">in</span> <span class=\"nv\">question.choice_set.all</span> <span class=\"cp\">%}</span>\n    <span class=\"p\">&lt;</span><span class=\"nt\">li</span><span class=\"p\">&gt;</span><span class=\"cp\">{{</span> <span class=\"nv\">choice.choice_text</span> <span class=\"cp\">}}</span> -- <span class=\"cp\">{{</span> <span class=\"nv\">choice.votes</span> <span class=\"cp\">}}</span> vote<span class=\"cp\">{{</span> <span class=\"nv\">choice.votes</span><span class=\"o\">|</span><span class=\"nf\">pluralize</span> <span class=\"cp\">}}</span><span class=\"p\">&lt;/</span><span class=\"nt\">li</span><span class=\"p\">&gt;</span>\n<span class=\"cp\">{%</span> <span class=\"k\">endfor</span> <span class=\"cp\">%}</span>\n<span class=\"p\">&lt;/</span><span class=\"nt\">ul</span><span class=\"p\">&gt;</span>\n\n<span class=\"p\">&lt;</span><span class=\"nt\">a</span> <span class=\"na\">href</span><span class=\"o\">=</span><span class=\"s\">&quot;</span><span class=\"cp\">{%</span> <span class=\"k\">url</span> <span class=\"s1\">&#39;polls:detail&#39;</span> <span class=\"nv\">question.id</span> <span class=\"cp\">%}</span><span class=\"s\">&quot;</span><span class=\"p\">&gt;</span>Vote again?<span class=\"p\">&lt;/</span><span class=\"nt\">a</span><span class=\"p\">&gt;</span>\n</code></pre></figure>\n<p>Μεταβείτε στη σελίδα <code class=\"docutils literal notranslate\"><span class=\"pre\">/polls/1/</span></code> και ψηφίστε. Κάθε φορά που ψηφίζετε θα βλέπετε τη σελίδα με τα αποτελέσματα της ερώτησης. Αν κάνετε submit τη φόρμα δίχως να επιλέξετε κάποια απάντηση θα δείτε ένα μήνυμα σφάλματος.</p>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Σημείωση</p>\n<p>Ο κώδικας του view <code class=\"docutils literal notranslate\"><span class=\"pre\">vote()</span></code> έχει ένα μικρό προβληματάκι. Πρώτα ρωτάει την database (μέσω της <code class=\"docutils literal notranslate\"><span class=\"pre\">get()</span></code>) για την ύπαρξη του <code class=\"docutils literal notranslate\"><span class=\"pre\">choice</span></code> με το συγκεκριμένο ID και αν βρεθεί επιστρέφει το ανάλογο object που είναι instance της <code class=\"docutils literal notranslate\"><span class=\"pre\">polls.models.Choice</span></code> class. Το object αυτό το ονομάζουμε <code class=\"docutils literal notranslate\"><span class=\"pre\">selected_choice</span></code>. Κατόπιν υπολογίζουμε τη νέα τιμή του <code class=\"docutils literal notranslate\"><span class=\"pre\">votes</span></code> και μετά αποθηκεύουμε τη νέα τιμή (αυξημένη κατά ένα) πίσω στην βάση δεδομένων. Εδώ όμως δημιουργείται πρόβλημα. Αν δύο χρήστες προσπαθήσουν να ψηφίσουν στην ίδια ερώτηση <em>ακριβώς την ίδια χρονική στιγμή</em>, τότε δεν θα δουλέψει όπως πρέπει: Η ίδια τιμή, ας πούμε 42, θα είναι η αρχική (<code class=\"docutils literal notranslate\"><span class=\"pre\">votes</span></code>) και για τους δύο χρήστες. Τότε και στους δύο, η νέα τιμή 43 θα εμφανιστεί ως αποτέλεσμα, αλλά η τιμή 44 θα έπρεπε να είναι η αναμενόμενη (που δεν είναι).</p>\n<p>Αυτό ονομάζεται <em>race condition</em>. Αν ενδιαφέρεστε μπορείτε να διαβάσετε την αναφορά στο <a class=\"reference internal\" href=\"/el/3.1/ref/models/expressions/#avoiding-race-conditions-using-f\"><span class=\"std std-ref\">αποφεύγοντας τα race conditions χρησιμοποιώντας την F</span></a> για να μάθετε πως μπορείτε να αποφύγετε τέτοιες (ακραίες) καταστάσεις.</p>\n</aside>\n</section>\n<section id=\"use-generic-views-less-code-is-better\">\n<h2>Χρήση των generic views: Ο λιγότερος κώδικας είναι καλύτερος<a class=\"heading-anchor\" href=\"#use-generic-views-less-code-is-better\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>The <code class=\"docutils literal notranslate\"><span class=\"pre\">detail()</span></code> (from <a class=\"reference internal\" href=\"/el/3.1/intro/tutorial03/\"><span class=\"doc\">Tutorial 3</span></a>) and <code class=\"docutils literal notranslate\"><span class=\"pre\">results()</span></code>\nviews are very short – and, as mentioned above, redundant. The <code class=\"docutils literal notranslate\"><span class=\"pre\">index()</span></code>\nview, which displays a list of polls, is similar.</p>\n<p>Αυτά τα views αναπαριστούν μια κοινή πρακτική γενικά στο Web development: φέρνουν data από την database ανάλογα τις παραμέτρους που εισήχθησαν στο URL, φορτώνουν ένα template και επιστρέφουν ένα rendered template. Επειδή αυτό είναι τόσο κοινότυπο, το Django προσφέρει μια συντόμευση, η οποία ονομάζεται σύστημα «generic views».</p>\n<p>Τα generic views απλοποιούν αυτές τις τόσο συνηθισμένες τακτικές σε βαθμό που δεν χρειάζεται να γράψετε καθόλου Python κώδικα για να φτιάξετε ένα app.</p>\n<p>Let’s convert our poll app to use the generic views system, so we can delete a\nbunch of our own code. We’ll have to take a few steps to make the conversion.\nWe will:</p>\n<ol class=\"arabic simple\">\n<li><p>Μετατροπή των URLconf.</p></li>\n<li><p>Διαγραφή παλιού κώδικα, αχρησιμοποίητα views.</p></li>\n<li><p>Εισαγωγή σε νέου είδους views, βασισμένα πάνω στα generic views του Django.</p></li>\n</ol>\n<p>Συνεχίστε να διαβάζετε για λεπτομέρειες.</p>\n<aside class=\"admonition-why-the-code-shuffle admonition\">\n<p class=\"admonition-title\">Γιατί αυτή η σύγχυση με τον κώδικα;</p>\n<p>Σε γενικές γραμμές, όταν γράφετε ένα Django app, θα καταλάβετε από την αρχή αν θα πρέπει να χρησιμοποιήσετε τα generic views (για την επίλυση του προβλήματος σας), παρά να φτάσετε στο τέλος και μετά να ξαναγράψετε τον κώδικα (όπως κάναμε εμείς τώρα). Εδώ ακολουθήσαμε αυτή την τακτική προκειμένου να σας δείξουμε πως γράφετε ένα view “με το δύσκολο τρόπο” προκειμένου να επικεντρωθείτε σε βασικά concepts.</p>\n<p>Θα πρέπει να γνωρίζετε βασικά μαθηματικά προτού χρησιμοποιήσετε το κομπιουτεράκι.</p>\n</aside>\n<section id=\"amend-urlconf\">\n<h3>Βελτιώση του URLconf<a class=\"heading-anchor\" href=\"#amend-urlconf\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>Ανοίξτε πρώτα το URLconf αρχείο <code class=\"docutils literal notranslate\"><span class=\"pre\">polls/urls.py</span></code> και αλλάξτε το σε:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\">polls/urls.py</figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.urls</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">path</span>\n\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">.</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">views</span>\n\n<span class=\"n\">app_name</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;polls&#39;</span>\n<span class=\"n\">urlpatterns</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n    <span class=\"n\">path</span><span class=\"p\">(</span><span class=\"s1\">&#39;&#39;</span><span class=\"p\">,</span> <span class=\"n\">views</span><span class=\"o\">.</span><span class=\"n\">IndexView</span><span class=\"o\">.</span><span class=\"n\">as_view</span><span class=\"p\">(),</span> <span class=\"n\">name</span><span class=\"o\">=</span><span class=\"s1\">&#39;index&#39;</span><span class=\"p\">),</span>\n    <span class=\"n\">path</span><span class=\"p\">(</span><span class=\"s1\">&#39;&lt;int:pk&gt;/&#39;</span><span class=\"p\">,</span> <span class=\"n\">views</span><span class=\"o\">.</span><span class=\"n\">DetailView</span><span class=\"o\">.</span><span class=\"n\">as_view</span><span class=\"p\">(),</span> <span class=\"n\">name</span><span class=\"o\">=</span><span class=\"s1\">&#39;detail&#39;</span><span class=\"p\">),</span>\n    <span class=\"n\">path</span><span class=\"p\">(</span><span class=\"s1\">&#39;&lt;int:pk&gt;/results/&#39;</span><span class=\"p\">,</span> <span class=\"n\">views</span><span class=\"o\">.</span><span class=\"n\">ResultsView</span><span class=\"o\">.</span><span class=\"n\">as_view</span><span class=\"p\">(),</span> <span class=\"n\">name</span><span class=\"o\">=</span><span class=\"s1\">&#39;results&#39;</span><span class=\"p\">),</span>\n    <span class=\"n\">path</span><span class=\"p\">(</span><span class=\"s1\">&#39;&lt;int:question_id&gt;/vote/&#39;</span><span class=\"p\">,</span> <span class=\"n\">views</span><span class=\"o\">.</span><span class=\"n\">vote</span><span class=\"p\">,</span> <span class=\"n\">name</span><span class=\"o\">=</span><span class=\"s1\">&#39;vote&#39;</span><span class=\"p\">),</span>\n<span class=\"p\">]</span>\n</code></pre></figure>\n<p>Note that the name of the matched pattern in the path strings of the second and\nthird patterns has changed from <code class=\"docutils literal notranslate\"><span class=\"pre\">&lt;question_id&gt;</span></code> to <code class=\"docutils literal notranslate\"><span class=\"pre\">&lt;pk&gt;</span></code>.</p>\n</section>\n<section id=\"amend-views\">\n<h3>Βελτίωση των views<a class=\"heading-anchor\" href=\"#amend-views\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>Επόμενο βήμα είναι να αφαιρέσουμε τα παλιά (πλέον) <code class=\"docutils literal notranslate\"><span class=\"pre\">index</span></code>, <code class=\"docutils literal notranslate\"><span class=\"pre\">detail</span></code> και <code class=\"docutils literal notranslate\"><span class=\"pre\">results</span></code> views και να χρησιμοποιήσουμε τα generic views του Django. Για να γίνει αυτό, ανοίξτε το αρχείο <code class=\"docutils literal notranslate\"><span class=\"pre\">polls/views.py</span></code> και αλλάξτε το σε:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\">polls/views.py</figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.http</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">HttpResponseRedirect</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.shortcuts</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">get_object_or_404</span><span class=\"p\">,</span> <span class=\"n\">render</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.urls</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">reverse</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.views</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">generic</span>\n\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">Choice</span><span class=\"p\">,</span> <span class=\"n\">Question</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">IndexView</span><span class=\"p\">(</span><span class=\"n\">generic</span><span class=\"o\">.</span><span class=\"n\">ListView</span><span class=\"p\">):</span>\n    <span class=\"n\">template_name</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;polls/index.html&#39;</span>\n    <span class=\"n\">context_object_name</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;latest_question_list&#39;</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">get_queryset</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n<span class=\"w\">        </span><span class=\"sd\">&quot;&quot;&quot;Return the last five published questions.&quot;&quot;&quot;</span>\n        <span class=\"k\">return</span> <span class=\"n\">Question</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">order_by</span><span class=\"p\">(</span><span class=\"s1\">&#39;-pub_date&#39;</span><span class=\"p\">)[:</span><span class=\"mi\">5</span><span class=\"p\">]</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">DetailView</span><span class=\"p\">(</span><span class=\"n\">generic</span><span class=\"o\">.</span><span class=\"n\">DetailView</span><span class=\"p\">):</span>\n    <span class=\"n\">model</span> <span class=\"o\">=</span> <span class=\"n\">Question</span>\n    <span class=\"n\">template_name</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;polls/detail.html&#39;</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">ResultsView</span><span class=\"p\">(</span><span class=\"n\">generic</span><span class=\"o\">.</span><span class=\"n\">DetailView</span><span class=\"p\">):</span>\n    <span class=\"n\">model</span> <span class=\"o\">=</span> <span class=\"n\">Question</span>\n    <span class=\"n\">template_name</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;polls/results.html&#39;</span>\n\n\n<span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">vote</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">,</span> <span class=\"n\">question_id</span><span class=\"p\">):</span>\n    <span class=\"o\">...</span> <span class=\"c1\"># same as above, no changes needed.</span>\n</code></pre></figure>\n<p>Χρησιμοποιούμε δύο generic views:\nΤο <a class=\"reference internal\" href=\"/el/3.1/ref/class-based-views/generic-display/#django.views.generic.list.ListView\" title=\"django.views.generic.list.ListView\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">ListView</span></code></a> και το <a class=\"reference internal\" href=\"/el/3.1/ref/class-based-views/generic-display/#django.views.generic.detail.DetailView\" title=\"django.views.generic.detail.DetailView\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">DetailView</span></code></a>. Αντίστοιχα, αυτά τα δύο views απλοποιούν τα concepts της «προβολής μια λίστας από objects» και της «προβολής μιας σελίδας λεπτομερειών για ένα συγκεκριμένου τύπου object.»</p>\n<ul class=\"simple\">\n<li><p>Κάθε generic view χρειάζεται να γνωρίζει το μοντέλο με το οποίο θα συνεργαστεί. Αυτό επιτυγχάνεται με το attribute <code class=\"docutils literal notranslate\"><span class=\"pre\">model</span></code>.</p></li>\n<li><p>Το <a class=\"reference internal\" href=\"/el/3.1/ref/class-based-views/generic-display/#django.views.generic.detail.DetailView\" title=\"django.views.generic.detail.DetailView\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">DetailView</span></code></a> generic view περιμένει μια τιμή ενός primary key (ID, αν θέλετε) η οποία έχει “αιχμαλωτιστεί” στο URL υπό το όνομα <code class=\"docutils literal notranslate\"><span class=\"pre\">&quot;pk&quot;</span></code>. Αυτός είναι ο λόγος που μετονομάσαμε το <code class=\"docutils literal notranslate\"><span class=\"pre\">question_id</span></code> σε <code class=\"docutils literal notranslate\"><span class=\"pre\">pk</span></code>.</p></li>\n</ul>\n<p>Από προεπιλογή, το generic view <a class=\"reference internal\" href=\"/el/3.1/ref/class-based-views/generic-display/#django.views.generic.detail.DetailView\" title=\"django.views.generic.detail.DetailView\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">DetailView</span></code></a> χρησιμοποιεί ένα template με το όνομα <code class=\"docutils literal notranslate\"><span class=\"pre\">&lt;appname&gt;/&lt;modelname&gt;_detail.html</span></code>. Στην περίπτωση μας θα χρησιμοποιήσει το template με το όνομα <code class=\"docutils literal notranslate\"><span class=\"pre\">&quot;polls/question_detail.html&quot;</span></code>. Μπορούμε να παρακάμψουμε (override) αυτή τη συμπεριφορά, θέτοντας την τιμή του attribute <code class=\"docutils literal notranslate\"><span class=\"pre\">template_name</span></code> σε μια δική μας. Ορίζουμε, επίσης, ένα δικό μας <code class=\"docutils literal notranslate\"><span class=\"pre\">template_name</span></code> και για το view <code class=\"docutils literal notranslate\"><span class=\"pre\">results</span></code> – αυτό εξασφαλίζει ότι το results view και το detail view θα έχουν διαφορετική εμφάνιση όταν γίνουν rendered, παρά το γεγονός ότι και τα δύο είναι τύπου <a class=\"reference internal\" href=\"/el/3.1/ref/class-based-views/generic-display/#django.views.generic.detail.DetailView\" title=\"django.views.generic.detail.DetailView\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">DetailView</span></code></a>.</p>\n<p>Ομοίως, το generic view <a class=\"reference internal\" href=\"/el/3.1/ref/class-based-views/generic-display/#django.views.generic.list.ListView\" title=\"django.views.generic.list.ListView\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">ListView</span></code></a> χρησιμοποιεί, εξ ορισμού, ένα template με το όνομα <code class=\"docutils literal notranslate\"><span class=\"pre\">&lt;appname&gt;/&lt;modelname&gt;_list.html</span></code>. Παρακάμπτουμε, και εδώ, τη συμπεριφορά αυτή θέτοντας τη τιμή του attribute <code class=\"docutils literal notranslate\"><span class=\"pre\">template_name</span></code> στο string <code class=\"docutils literal notranslate\"><span class=\"pre\">&quot;polls/index.html&quot;</span></code>, το οποίο έχουμε ήδη υλοποιήσει.</p>\n<p>In previous parts of the tutorial, the templates have been provided\nwith a context that contains the <code class=\"docutils literal notranslate\"><span class=\"pre\">question</span></code> and <code class=\"docutils literal notranslate\"><span class=\"pre\">latest_question_list</span></code>\ncontext variables. For <code class=\"docutils literal notranslate\"><span class=\"pre\">DetailView</span></code> the <code class=\"docutils literal notranslate\"><span class=\"pre\">question</span></code> variable is provided\nautomatically – since we’re using a Django model (<code class=\"docutils literal notranslate\"><span class=\"pre\">Question</span></code>), Django\nis able to determine an appropriate name for the context variable.\nHowever, for ListView, the automatically generated context variable is\n<code class=\"docutils literal notranslate\"><span class=\"pre\">question_list</span></code>. To override this we provide the <code class=\"docutils literal notranslate\"><span class=\"pre\">context_object_name</span></code>\nattribute, specifying that we want to use <code class=\"docutils literal notranslate\"><span class=\"pre\">latest_question_list</span></code> instead.\nAs an alternative approach, you could change your templates to match\nthe new default context variables – but it’s a lot easier to tell Django to\nuse the variable you want.</p>\n<p>Τρέξτε τον server και παίξτε με τη νέα σας εφαρμογή που είναι βασισμένη στα generic views.</p>\n<p>Για όλες τις λεπτομέρειες πάνω στα generic views, δείτε το άρθρο <a class=\"reference internal\" href=\"/el/3.1/topics/class-based-views/\"><span class=\"doc\">εγχειρίδιο (documentation) των generic views</span></a>.</p>\n<p>Όταν είστε εξοικειωμένοι με τις φόρμες και τα generic views διαβάστε το <a class=\"reference internal\" href=\"/el/3.1/intro/tutorial05/\"><span class=\"doc\">πέμπτο μέρος αυτού του οδηγού</span></a> για να μάθετε πως να κάνετε τεστ (test) στην εφαρμογή σας.</p>\n</section>\n</section>","rootId":"writing-your-first-django-app-part-4","toc":[{"title":"Write a minimal form","anchor":"write-a-minimal-form","children":[]},{"title":"Χρήση των generic views: Ο λιγότερος κώδικας είναι καλύτερος","anchor":"use-generic-views-less-code-is-better","children":[{"title":"Βελτιώση του URLconf","anchor":"amend-urlconf","children":[]},{"title":"Βελτίωση των views","anchor":"amend-views","children":[]}]}],"breadcrumbs":[{"docname":"intro/index","title":"Ξεκινώντας","url":"/el/3.1/intro/"}],"prev":{"docname":"intro/tutorial03","title":"Γράφοντας το πρώτο σας Django app, μέρος 3","url":"/el/3.1/intro/tutorial03/"},"next":{"docname":"intro/tutorial05","title":"Γράφοντας το πρώτο σας Django app, μέρος 5","url":"/el/3.1/intro/tutorial05/"},"formats":{"html":"/el/3.1/intro/tutorial04/","markdown":"/el/3.1/intro/tutorial04.md","json":"/el/3.1/intro/tutorial04.json"},"source":"https://github.com/django/django/blob/stable/3.1.x/docs/intro/tutorial04.txt","official":"https://docs.djangoproject.com/el/3.1/intro/tutorial04/","inVersions":["6.1","6.0","5.2","5.1","5.0","4.2","4.1","4.0","3.2","3.1","3.0","2.2","2.1","2.0","1.11","1.10"],"inLocales":["en","zh-hans","fr","ja","id","pt-br","ko","es","el","pl"]}