uMtMu
Table of Contents
- 1. Yol
- 1.1. Writing your first Django app, part 1
- 1.2. Writing your first Django app, part 2
- 1.3. Writing your first Django app, part 3
- 1.4. Writing your first Django app, part 4
- 1.5. Writing your first Django app, part 5
- 1.6. Writing your first Django app, part 6
- 1.7. Writing your first Django app, part 7
- 1.8. Yerelleştirme ve Çeviri
- 2. Araştırılacak
[0/3]
- 3. Bağlantılar
1 Yol
1.1 Writing your first Django app, part 1
1.1.1 Virtul Env
1.1.2 Projenin oluşturulması
django_env/
… mydj_sites/
root directory is just a container for your project. Its name doesn’t matter to Django; you can rename it to anything you like.
├── manage.py
A command-line utility that lets you interact with this Django project in various ways.
└── mydj_sites
directory is the actual Python package for your project. Its name is the
Python package name you’ll need to use to import anything inside it
├── init.py
├── settings.py
├── urls.py
└── wsgi.py
1.1.3 Geliştirme sunucusu
python manage.py runserver
Performing system checks…
System check identified no issues (0 silenced).
You have 13 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
Run 'python manage.py migrate' to apply them.
September 04, 2016 - 18:52:28
Django version 1.10.1, using settings 'mydj_sites.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
1.1.4 İlk uygulamanın oluşturulması
Oluşan dizin yapısı polls/
├── admin.py
├── apps.py
├── init.py
├── migrations
│ └── init.py
├── models.py
├── tests.py
└── views.py
1.1.5 İlk view'ın oluşturulması
nilbody
1.1.6 polls dizini altında urls.py dosyasının oluşturulması
url(r'^$', views.index, name='index'), ]
1.1.7 mydj_sites/mydj_sites/mydj_sites dizinindeki urls.py içeriğine yönlendirme ekleme
url(r'^polls/', include('polls.urls')), url(r'^admin/', admin.site.urls), ]
1.2 Writing your first Django app, part 2
1.2.1 Veri tabanının ayarlanması mydj_sites/mydj_sites/mydj_sites/settings.py dosyası içerisinde veri tabanı olarak sqlite seçili. INSTALLED_APPS dizisi içerisinde belirlenmiş uygulamalar için veri tabanında tablolar oluşturulmalı.
1.2.2 Veri tabanı modellerinin oluşturulması polls/models.py
nilbody
1.2.3 Modellerin aktive edilmesi
Veri tabanı şemasının oluşturulması
Veri tabanı objelerinin oluşturulması
Yukarıda belirtilen eylemler, polls uygulamasının mydj_sites/mydj_sites/mydj_sites/settings.py dosyası INSTALLED_APPS
listesinin içerisine "'polls.apps.PollsConfig'," olarak eklenmesi gerekir.
makemigrations komutu ile yeni eklenen uygulamalar olduğunu ve bu uygulamalar için gerekli veri tabanı değişikliklerinin yapılacağı bilgisi verilmektedir. Daha önce bu işlem için south uygulaması kullanılmıştı. Bu yöntem ile veri tabanı değişiklikleri sürüm kontrol sistemi altında tutulmuş. python manage.py makemigrations polls
Migrations for 'polls':
polls/migrations/0001_initial.py:
- Create model Choice
- Create model Question
- Add field question to choice polls/migrations/0001_initial.py dosyasının aldında ilgili migration ile ilgili işlemler bulunmaktadır.
1.2.4 API ile oynamak ??
>>> import django >>> django.setup() >>> from polls.models import Question, Choice # Import the model classes we just wrote. # No questions are in the system yet. >>> Question.objects.all() <QuerySet []> # Create a new Question. # Support for time zones is enabled in the default settings file, so # Django expects a datetime with tzinfo for pub_date. Use timezone.now() # instead of datetime.datetime.now() and it will do the right thing. >>> from django.utils import timezone >>> q = Question(question_text="What's new?", pub_date=timezone.now()) # Save the object into the database. You have to call save() explicitly. >>> q.save() # Now it has an ID. Note that this might say "1L" instead of "1", depending # on which database you're using. That's no biggie; it just means your # database backend prefers to return integers as Python long integer # objects. >>> q.id 1 # Access model field values via Python attributes. >>> q.question_text "What's new?" >>> q.pub_date datetime.datetime(2012, 2, 26, 13, 0, 0, 775217, tzinfo=<UTC>) # Change values by changing the attributes, then calling save(). >>> q.question_text = "What's up?" >>> q.save() # objects.all() displays all the questions in the database. >>> Question.objects.all() <QuerySet [<Question: Question object>]>
>>> from polls.models import Question, Choice # Make sure our __str__() addition worked. >>> Question.objects.all() <QuerySet [<Question: What's up?>]> # Django provides a rich database lookup API that's entirely driven by # keyword arguments. >>> Question.objects.filter(id=1) <QuerySet [<Question: What's up?>]> >>> Question.objects.filter(question_text__startswith='What') <QuerySet [<Question: What's up?>]> # Get the question that was published this year. >>> from django.utils import timezone >>> current_year = timezone.now().year >>> Question.objects.get(pub_date__year=current_year) <Question: What's up?> # Request an ID that doesn't exist, this will raise an exception. >>> Question.objects.get(id=2) Traceback (most recent call last): ... DoesNotExist: Question matching query does not exist. # Lookup by a primary key is the most common case, so Django provides a # shortcut for primary-key exact lookups. # The following is identical to Question.objects.get(id=1). >>> Question.objects.get(pk=1) <Question: What's up?> # Make sure our custom method worked. >>> q = Question.objects.get(pk=1) >>> q.was_published_recently() True # Give the Question a couple of Choices. The create call constructs a new # Choice object, does the INSERT statement, adds the choice to the set # of available choices and returns the new Choice object. Django creates # a set to hold the "other side" of a ForeignKey relation # (e.g. a question's choice) which can be accessed via the API. >>> q = Question.objects.get(pk=1) # Display any choices from the related object set -- none so far. >>> q.choice_set.all() <QuerySet []> # Create three choices. >>> q.choice_set.create(choice_text='Not much', votes=0) <Choice: Not much> >>> q.choice_set.create(choice_text='The sky', votes=0) <Choice: The sky> >>> c = q.choice_set.create(choice_text='Just hacking again', votes=0) # Choice objects have API access to their related Question objects. >>> c.question <Question: What's up?> # And vice versa: Question objects get access to Choice objects. >>> q.choice_set.all() <QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]> >>> q.choice_set.count() 3 # The API automatically follows relationships as far as you need. # Use double underscores to separate relationships. # This works as many levels deep as you want; there's no limit. # Find all Choices for any question whose pub_date is in this year # (reusing the 'current_year' variable we created above). >>> Choice.objects.filter(question__pub_date__year=current_year) <QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]> # Let's delete one of the choices. Use delete() for that. >>> c = q.choice_set.filter(choice_text__startswith='Just hacking') >>> c.delete()
1.2.5 Django Admin
1.3 Writing your first Django app, part 3
1.3.1 Başlıklar
- Blog homepage – displays the latest few entries.
- Entry “detail” page – permalink page for a single entry.
- Year-based archive page – displays all months with entries in the given year.
- Month-based archive page – displays all days with entries in the given month.
- Day-based archive page – displays all entries in the given day.
- Comment action – handles posting comments to a given entry.
In our poll application, we’ll have the following four views:
- Question “index” page – displays the latest few questions.
- Question “detail” page – displays a question text, with no results but with a form to vote.
- Question “results” page – displays results for a particular question.
- Vote action – handles voting for a particular choice in a particular question.
1.3.2 Daha fazla view polls/views.py
nilbody
polls/urls.py
# ex: /polls/ url(r'^$', views.index, name='index'), # ex: /polls/5/ url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'), # ex: /polls/5/results/ url(r'^(?P<question_id>[0-9]+)/results/$', views.results, name='results'), # ex: /polls/5/vote/ url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'), ]
polls/views.py
nilbody
View kulllanımındaki problem sayfa tasarımının hard-coded olarak yapılmış olmasıdır. Bunun önüne geçmek için django template dili kullanılabilir.
polls/templates/polls/index.html
{% 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 %}
Şimdi de polls/views.py dosyamızın oluşturduğumuz template'i kullanmasını sağlayalım.
polls/views.py
nilbody
1.3.3 Bir kısayol: render()
polls/views.py
nilbody
HttpResponse(template.render(context, request)) yerine return render(request, 'polls/index.html', context) kulllandık. Ayrıca loader
ve HttpReponse yerine sadece render import etmemiz yeterli oldu. Ancak render gerektirmeyen static sayfalarınız için hala loader ve HttpResponse sınıflarını kullanmanız gerekir.
1.3.4 404 hatası oluşturmak polls/views.py
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})
polls/templates/polls/detail.html
{{ question }}
1.3.5 Bir başka kısayol: get_object_or_404()
polls/views.py
# ... def detail(request, question_id): question = get_object_or_404(Question, pk=question_id) return render(request, 'polls/detail.html', {'question': question})
1.3.6 template sistemini kullanalım polls/templates/polls/detail.html
<h1>{{ question.question_text }}</h1> <ul> {% for choice in question.choice_set.all %} <li>{{ choice.choice_text }}</li> {% endfor %} </ul>
1.3.7 Hardcoded URL'lerin kaldırılması polls/templates/polls/index.html
#<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li> <li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
1.3.8 URL isim uzaylarının oluşturulması polls uygulamasında "details" url'i olduğu gibi başka bir uygulamada da
"details" url'i olabilir. Djangonun bunu ayırt edebilmesi için aşağıdaki işlemler yapılmalıdır. polls/urls.py
urlpatterns = [ url(r'^$', views.index, name='index'), url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'), url(r'^(?P<question_id>[0-9]+)/results/$', views.results, name='results'), url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'), ]
polls/templates/polls/index.html
/*<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>*/ <li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>
1.4 Writing your first Django app, part 4
1.4.1 Basit bir form
polls/templates/polls/detail.html
<h1>{{ question.question_text }}</h1> {% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %} <form action="{% url 'polls:vote' question.id %}" method="post"> {% csrf_token %} {% for choice in question.choice_set.all %} <input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}" /> <label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br /> {% endfor %} <input type="submit" value="Vote" /> </form>
polls/views.py
# ... def vote(request, question_id): question = get_object_or_404(Question, pk=question_id) try: selected_choice = question.choice_set.get(pk=request.POST['choice']) except (KeyError, Choice.DoesNotExist): # Redisplay the question voting form. return render(request, 'polls/detail.html', { 'question': question, 'error_message': "You didn't select a choice.", }) else: selected_choice.votes += 1 selected_choice.save() # Always return an HttpResponseRedirect after successfully dealing # with POST data. This prevents data from being posted twice if a # user hits the Back button. return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))
polls/views.py
nilbody
polls/templates/polls/results.html
<h1>{{ question.question_text }}</h1> <ul> {% for choice in question.choice_set.all %} <li>{{ choice.choice_text }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}</li> {% endfor %} </ul> <a href="{% url 'polls:detail' question.id %}">Vote again?</a>
1.4.2 Generic viewlar
These views represent a common case of basic Web development:
- getting data from the database according to a parameter passed in the URL,
- loading a template and returning the rendered template.
Because this is so common, Django provides a shortcut, called the “generic views” system.
- urls.py'nin güncellenmesi polls/urls.py
urlpatterns = [ url(r'^$', views.IndexView.as_view(), name='index'), url(r'^(?P<pk>[0-9]+)/$', views.DetailView.as_view(), name='detail'), url(r'^(?P<pk>[0-9]+)/results/$', views.ResultsView.as_view(), name='results'), url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'), ]
Önemli url(r'^(?P<pk>[0-9]+)/$', views.DetailView.as_view(), name='detail'), <pk> yazan yerde daha önceden <question_id> yazıyordu. Bu değişikliğin sebebi, generic viewların primary_key ile çalışıyor olması
- views.py'nin güncellenmesi polls/views.py
nilbody
DetailView varsayılan olarak <app name>/templates/<app name>/<model name>_detail.html dosyasını template olarak kullanır. Bizim durumumuzda bu dosya question_detail.html olacaktı. template_name değişkeni ile bunu değiştirdik.
Aynı şekilde ListView de varsayılan olarak <app name>/templates/<app name>/<model name>_list.html kullanacaktı.
1.5 Writing your first Django app, part 5
1.5.1 Otomatik testler (ilginç bir konu)
- Neden test?
Otomatik testler 3 farklı fazda yazılabilir. Başta, sonda, ortada :D
We identify a bug
Fortunately, there’s a little bug in the polls application for us to fix right away: the Question.was_published_recently() method returns True if the
Question was published within the last day (which is correct) but also if the Question’s pub_date field is in the future (which certainly isn’t).
- Nasıl test?
>>> import datetime >>> from django.utils import timezone >>> from polls.models import Question >>> # create a Question instance with pub_date 30 days in the future >>> future_question = Question(pub_date=timezone.now() + datetime.timedelta(days=30)) >>> # was it published recently? >>> future_question.was_published_recently() True
Yukarıda görüldüğü gibi yayın tarihi gelecekte olan bir soru için de yakın zamanda yayınlanmış cevabı dönüyor. polls/test.py
nilbody
Testlerin çalıştırılması
1.5.2 Bug'ın düzeltilmesi polls/models.py
nilbody
1.5.3 Daha karmaşık örnekler
While we’re here, we can further pin down the was_published_recently()
method; in fact, it would be positively embarrassing if in fixing one bug we had introduced another.
polls/test.py
nilbody
Bu genişletme ile bu metodun tarih bazında bütün olası girdilerine karşı çıktıları kontrol edilmiş oldu.
1.5.4 View'ı test etmek
- Django test istemcisi
Djangonun sunduğu test istemcisini test.py dosyası üzerinden ya da shell üzerinden kullanabiliriz.
Shell üzerinden test.py üzerinden denemeden farklı olarak aşağıdaki iki satır gerekir.
>>> from django.test.utils import setup_test_environment >>> setup_test_environment()
setup_test_environment() installs a template renderer which will allow us to examine some additional attributes on responses such as response.context that otherwise wouldn’t be available. Note that this method does not setup a test database, so the following will be run against the existing database and the output may differ slightly depending on what questions you already created. You might get unexpected results if your TIME_ZONE in settings.py isn’t correct. If you don’t remember setting it earlier, check it before continuing.
>>> from django.test.utils import setup_test_environment >>> setup_test_environment() >>> from django.test import Client >>> # create an instance of the client for our use >>> client = Client() >>> # get a response from '/' >>> response = client.get('/') >>> # we should expect a 404 from that address >>> response.status_code 404 >>> # on the other hand we should expect to find something at '/polls/' >>> # we'll use 'reverse()' rather than a hardcoded URL >>> from django.urls import reverse >>> response = client.get(reverse('polls:index')) >>> response.status_code 200 >>> response.content b'\n <ul>\n \n <li><a href="/polls/1/">What's up?</a></li>\n \n </ul>\n\n' >>> # If the following doesn't work, you probably omitted the call to >>> # setup_test_environment() described above >>> response.context['latest_question_list'] <QuerySet [<Question: What's up?>]>
1.5.5 View'ı geliştirelim polls/views.py
nilbody
1.5.6 View için otomatik test yazalım
nilbody
1.5.7 DetailView için test yazılması polls/views.py
nilbody
polls/test.py
nilbody
1.6 Writing your first Django app, part 6
1.6.1 Templateler üzerine deneme (CSS ekleme)
- görüntü ekleme
- mydj_sites/mydj_sites/mydj_sites/settings.py dosyasında INSTALLED_APPS listesinde django.contrib.staticfiles yoksa eklenecek.
- 1. adımdaki dosyada STATIC_URL='static' olarak tanımlanacak.
- static dosyalar polls/static/polls dizini altında olacak. Örnek olarak polls/static/polls/survey.jpg
- polls/templates/polls/index.html
{% load static %} <img src="{% static "polls/survey.jpg" %}" alt="Oyları görelim"/> {% if latest_question_list %} <ul> {% for question in latest_question_list %} <li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li> {% endfor %} </ul> {% else %} <p>No polls are available.</p> {% endif %}
- mydj_sites/mydj_sites/mydj_sites/settings.py dosyasında INSTALLED_APPS listesinde django.contrib.staticfiles yoksa eklenecek.
- javascript ve css ekleme mydj_sites/mydj_sites/polls/static/polls
├── frontend.js
├── style.css
└── survey.jpg frontend.js
$( function() { $( "img" ).each( function() { var $img = $( this ); var img_scale = $img.width() / $img.height(); $img.width( $img.parent().width() ); $img.height( $img.height() * $img_scale ); }); } );
style.css
margin: auto; width: 50%; border: 3px solid green; padding: 10px; }
templates/index.html
{% load static %} <script src="https://code.jquery.com/jquery-3.1.0.min.js"></script> <script type="text/javascript" src="{% static "polls/frontend.js" %}"></script> <link rel="stylesheet" type="text/css" href="{% static "polls/style.css" %}"></script> <div class="center"> <img src="{% static "polls/survey.jpg" %}" alt="Oyları görelim"/> {% if latest_question_list %} <ul> {% for question in latest_question_list %} <li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li> {% endfor %} </ul> {% else %} <p>No polls are available.</p> {% endif %} </div>
1.7 Writing your first Django app, part 7
1.7.1 Admin panelinin düzenlenmesi
Daha önce "admin.site.register(Question)" ile Question modelini admin penceresine eklemiştik. polls/admin.py
nilbody
Yukarıdaki kod ile Question modelinin admin panelinde oluşturulması sırasında Field sıralamaları belirlenmiş oldu. polls/admin.py
nilbody
Yukarıdaki kod ile de ilgili alanlar gruplanabilir.
1.7.2 Choice modelinin admin paneline eklenmesi ve sonrası :D
Choice modelini aynı Question modelini eklediğimiz gibi
"admin.site.register(Choice)" şeklinde ekleyebiliriz. Böylelikle Choice nesnelerimizi de admin panelimizden ekleyebiliriz. Ancak görüldüğü gibi
Soruyu oluşturduktan sonra soruya ait cevapları ayrıca eklemek etkin bir yol değildir. Daha iyileştirmek için cevap ekleme seçeneklerini soru ekleme penceresine gömelim. polls/admin.py
nilbody
Sonuç nasıl oldu :) Fena değil. Ancak sorular aşağı doğru fazla yer kapladı. Bunun için "class ChoiceInline(admin.StackedInline):" satırındaki
StackedInline yerine TabularInline koyabiliriz.
1.7.3 Şimdi de Question listemizi düzenleyelim
Varsayılan olarak Model ana sayfamızdaki listede sadece modelin str fonksiyonunun çıktısı görüntülerinir. Bunun yanında faydalı alanları da gösterebiliriz.
polls/admin.py
nilbody
Bu penceredeki alan isimleri aşağıdaki şekilde düzenlenebilir. polls/models.py
nilbody
1.7.4 Admin penceresinde Question modellerinin süzülmesi ve arama polls/admin.py
search_fields = ['question_text']
1.7.5 Admin pencere template'inin düzenlenmesi
Create a templates directory in your project directory (the one that contains manage.py)
mydj_sites/mydj_sites/mydj_sites/settings.py
TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR, 'templates')], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ]
Şimdi django admin template dosyasını kendi templates/admin dizinimiz altına kopyalayacağız. Django şablonun bulunduğu dizini aşağıdaki şekilde bulabiliriz.
Yukarıdaki dizin altındaki "contrib/admin/templates/admin/base_site.html"
dosyayı mydj_sites/mydj_sites/templates/admin dizini altına kopyalayalım. İçeriği aşağıdaki gibi
{% extends "admin/base.html" %} {% block title %}{{ title }} | {{ site_title|default:_('Django site admin') }}{% endblock %} {% block branding %} <h1 id="site-name"><a href="{% url 'admin:index' %}">{{ site_header|default:_('Django administration') }}</a></h1> {% endblock %} {% block nav-global %}{% endblock %}
1.8 Yerelleştirme ve Çeviri
1.8.1 Giriş
Django projelerinin yerelleştirilebilir olması için çevirilmesi gereken string alanlar için bu alanlar translation strings adı verilen kancalar koymamız gerekir.
Bundan sonra Django tüm projeden bu alanları çekerek message file dosyası oluşturur. Bu dosya içerisinden ilgili dil için gerekli çeviriler kolaylıkla yapılabilir. Bu dosya derlendikten sonra Django çalışma sırasında dil değişimi yapabilir.
Yerelleştirme Djangoda varsayılan olarak açıktır. Kullanılmak istenmiyorsa settings.py dosyasındaki USE_I18N = FALSE olarak ayarlanabilir.
Yerelleştirmee konusunda bir noktada yerel biçimlerin düzenlenmesidir. Bildindiği gibi farklı ülkelerde tarih ve ondalık ayraç gösterimi farklı olabilir. Bunun için USE_L10N ayarlaması yapılmalıdır.
Projeniz için çevirinin aktif olup olmadığını kontrol etmek için settings.py dosyasında MIDDLEWARE
dizisinde django.middleware.locale.LocaleMiddleware olup olmadığını kontrol edebilirsiniz.
1.8.2 Çeviri: Python kodu içinde
- Standart çeviri
ugettext() fonksiyonu ile translation string ler belirlenir. Fonsiyonun kısayolu olarak (_) kullanılabilir. Python'un interaktif shell uygulaması _ karakterini son sonuç olarak tanımladığı için kullanım sırasında ugettext() _() olarak tekrar import edilerek sorun çözülür. Örnek view
from django.http import HttpResponse def my_view(request): output = _("Welcome to my site.") return HttpResponse(output)
Çeviri kod içerisinde değişkenler ve hesaplanmış(join ile birleştirilmiş gibi) veriler üzerinde de uygulanabilir.
nilbody
Açıkcası hesaplanmış veri kısmını anlayamadım. ???
nilbody
Hemen altındaki uyarıda, Djangonun değişken ve hesaplanmış verilerdeki stringleri bulamadığını bunun için makemessages kullanıldığını yazmış. ???
nilbody
Yukarıdaki örnekte, farklı dillerdeki farklı kelime dizilişlerini yenmek için konumsal(positional) interpolasyon kullanmak yerine isimlendirilmiş(named-string) interpolasyon kullanmak gerektiğini gösteriyor.
nilbody
Yukarıdaki şekilde uzantısı \*.po olan messagefile içerisinde çevirmene yardımcı olacak çeviri metnine yorum satırı eklenebiliyor. Çıktısı aşağıdaki gibi.
#. Translators: This message appears on the home page only # path/to/python/file.py:123 msgid "Welcome to my site." msgstr ""
- Marking strings as no-op ???
2 Araştırılacak [0/3]
[ ]
Polls uygulamasında cevapları oluştururken verilen oy sayısı da belirlenebiliyor. Bu uygun olmaz. Varsayılan oy sayısının sıfır olarak belirlenmesi ve oluşturulurken bu değerin girilmemesini sağlamak iyi olur.
[ ]
utf-8 karakterlerin kullanabilmesi
[ ]
farklı dillerin esnek bir şekilde implemente edilmesi (Localization)