IUT 2019-2020 : cours JavaScript et jQuery
Bonjour à tous, voici les liens vers les PDFs des cours JavaScript et jQuery :
Tout ce qui concerne le développement en général, que ce soit des choses générales, ou des choses bien précises. Cela va de la gestion de projet à la recherche du fonctionnement de pointeurs en C.
Bonjour à tous, voici les liens vers les PDFs des cours JavaScript et jQuery :
Sur les versions de Django < 2.1, il était impossible de surcharger « correctement » l’administration.
admin.py
à la racine de votre projet (« à la racine », parce qu’il est « global » à tout le projet)from django.contrib import admin
class MyProjectAdminSite(admin.AdminSite):
title_header = 'My project Admin'
site_header = 'My project administration'
settings.py
, remplacez 'django.contrib.admin'
par 'my_app.apps.MyAppAdminConfig',
apps.py
de votre projet, soit my_project/my_app/apps.py
, déclarez l’administration comme suit :
from django.apps import AppConfig
from django.contrib.admin.apps import AdminConfig
class MyAppConfig(AppConfig):
name = 'my_app'
class MyAppAdminConfig(AdminConfig):
default_site = 'admin.MyProjectAdminSite'
Vidéo sur les expressions régulières en Python : liste Youtube de 15+ videos, de débutant jusqu’à niveau avancé (regardez la playlist sur la droite pour voir les 15) !
Vous voulez apprendre plein de petites astuces qui vont vous faire gagner énormément de temps sur Linux ?
Cliquez ici : tecmint !
Il y en a un autre excellent ici sur websauvage !
Cette astuce vient de Dan Bader. Du code, rapidement :
# Émuler ce que fait la std lib :
>>> import datetime
>>> aujourdhui = datetime.date.today()
# Le résultat de __str__ doit être lisible = comme une chaîne :
>>> str(today)
'2017-02-02'
# Le résultat de __repr__ doit lever les ambiguïtés possibles :
>>> repr(today)
'datetime.date(2017, 2, 2)'
# L'interpréteur Python en ligne de commande
# utilise __repr__ pour inspecter les objets :
>>> today
datetime.date(2017, 2, 2)
Voici un site extrêmement bien fait qui aide à apprendre les branches et le fonctionnement de ces dernières : learngitbranching
Un excellent article écrit par Dan Bader (j’ai pas mal discuté avec lui et j’ai son livre, il est vraiment aussi bon que modeste, je vous recommande vivement tous ses articles – et n’hésitez pas à lui parler en Anglais (tant qu’il n’est pas encore trop connu !), il vous répondra sûrement).
Il manque juste ces « petits » détails techniques lorsqu’on se base sur les modèles abstraits et l’héritage au sens « modèle » de Django (Abstract Base Model).
Prenons un exemple simple : vous créez un modèle « simple » Media(models.Model)
dont vous allez hériter sur deux modèles : Book(Media)
et Dvd(Media)
.
Ce qui va vous prendre beaucoup de temps (et qui n’est expliqué nulle part de manière claire et directe), c’est que Django, de manière cachée, va créer des propriétés qui vont dans les deux sens entre le modèle parent et le modèle enfant.
Pour reprendre notre exemple, avec les trois modèles : Media
= parent, et les deux enfants Book
et Dvd
.
Imaginez que pour chaque enfant, vous créiez une méthode spécifique, par exemple Book.nb_pages()
et Dvd.is_blue_ray()
De manière cachée, vous pourrez à partir du parent, accéder à l’enfant et ses propriété via son nom comme ceci :
my_media = Media.object.get(pk=1)
if hasattr(self, 'book'): # this Media is a Book:
my_media.book.nb_pages()
elif hasattr(self, 'dvd'): # this media is a Dvd:
my_media.dvd.is_blue_ray()
else: # direct Media model access:
pass
A l’inverse, à partir des modèles enfants, pour accéder au parent c’est le nom du modèle parent avec _ptr
:
my_book = Book.object.get(pk=21)
my_dvd = Dvd.object.get(pk=75)
# imaginons que "price" est une propriété de Media
property. On peut écrire :
print(my_book.media_ptr.price)
print(my_dvd.media_ptr.price)
En mode débug, un serveur Django renvoie tous les fichiers, y compris les fichiers statique. Seul problème : tous les fichiers statique on leur URL qui commence par /static/
.
Mais on rencontre un problème : le favicon.ico
n’est pas un fichier statique « normal » = qui commence par /static/
. C’est un nom « en dur », qui ressemble à http://monsite/favicon.ico
.
Il vous faut donc la coder en dur dans les URLs : ainsi : url(r'^favicon.ico/$',...)
Et pour renvoyer directement le contenu, il suffit de faire une fonction immédiate (= lambda
) qui renvoie directement le contenu :
urlpatterns = [
# ...blabla... all path and now:
url(r'^public/(?P
'document_root': settings.MEDIA_ROOT
}, name='url_public'),
url(r'^favicon.ico/$', # google chrome favicon fix :
lambda x: HttpResponseRedirect(settings.STATIC_URL+'favicon.ico')),
]
Django, nativement, a la possibilité de passer des dictionnaires clé-valeurs à tous les templates, et dans les templates on accède aux valeurs via la clé.
Exemple concret : je voulais passer le nom de mon site à tous les templates, mais sous forme de constante.
Dans settings.py
j’ai défini ma constante : WEBSITE_NAME = 'mywebsite'
Il suffit de créer une fonction qui renvoie un dictionnaire avec une clé nommée « correctement », par exemple :
def context_processor_website_name(request):
return {'website_name': WEBSITE_NAME}
Et ensuite, dans les context_processors
, juste ajouter le nom de la fonction par rapport au package où elle est.
J’ai mis cette fonction dans settings.py
.
Je ne sais pas si c’est la meilleure place mais l’idée c’est que comme c’est en rapport avec la configuration de mon site, c’est le meilleur endroit…
Donc pour préciser où est la fonction c’est 'myproject.settings.context_processor_website_name'
:
On retrouve donc le code final comme ceci :
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',
# ... and:
'myproject.settings.context_processor_website_name'
],
},
}, ]
Et voilà, à partir de maintenant, avec exactement 3 lignes de code, j’ai accès à ma variable website_name
, que je peux utiliser ainsi :
<title>{% block title %}{% if title %}{{ title|safe }} - {% endif %}{{ website_name }}{% endblock %}</title>
Petite parenthèse : grâce à ce code, si la page qu’on affiche a un titre, elle aura pour titre : [titre] - [nom du site]
et si elle n’a aucun titre, elle affichera : [nom du site]
DaysOfWeek
Après avoir écrit en trois parties (1, 2 et 3) comment faire un modèle sur mesure, voici le code source au complet.
from django.core.exceptions import ValidationError
from django import forms
from django.db import models
from django.utils.translation import ugettext_lazy as _
class DaysOfWeek:
DAYS = {1: _("Monday"),
2: _("Tuesday"),
3: _("Wednesday"),
4: _("Thursday"),
5: _("Friday"),
6: _("Saturday"),
7: _("Sunday"), }
DAYS_SHORT = {1: _("Mo"),
2: _("Tu"),
3: _("We"),
4: _("Th"),
5: _("Fr"),
6: _("Sa"),
7: _("Su"), }
CHOICES = [(idx, value) for idx, value in DAYS.items()]
@staticmethod
def summary_from_list(tab, empty=' '):
if tab is None:
return '-'.join([empty for a in range(len(DaysOfWeek.DAYS))])
return '-'.join([str(DaysOfWeek.DAYS_SHORT.get(i, empty)) for i in tab])
class DaysFormField(forms.TypedMultipleChoiceField):
# different widget, comment to change interface:
widget = forms.CheckboxSelectMultiple
def __init__(self, *args, **kwargs):
if 'max_length' in kwargs:
kwargs.pop('max_length')
kwargs['choices'] = DaysOfWeek.CHOICES
super().__init__(*args, **kwargs)
class DaysField(models.CharField):
description = _("Comma-separated integers between 1 and 7")
def __init__(self, *args, **kwargs):
kwargs['max_length'] = 13 # max. len = all days = "1,2,3,4,5,6,7" = 13
super().__init__(*args, **kwargs)
@staticmethod
def value_to_array(value):
if value is None:
return None
try:
if isinstance(value, list):
return [int(a) for a in value]
elif isinstance(value, str):
return [int(a) for a in value.split(',')]
except (TypeError, ValueError):
raise ValidationError(_("Unexpected value"))
raise ValidationError(_("Unexpected value"))
@staticmethod
def from_db_value(value, expression, connection):
return DaysField.value_to_array(value)
def to_python(self, value):
return DaysField.value_to_array(value)
def get_prep_value(self, value):
return ','.join([str(a) for a in value]) if value is not None else None
def formfield(self, **kwargs):
# ignore the admin directives: directly override with our custom form:
return super().formfield(form_class=DaysFormField,
initial=[])
# region - Validator -
class ListBetween1And7Validator:
def __call__(self, value):
try:
if isinstance(value, list):
loop = [int(a) for a in value]
elif isinstance(value, str):
loop = [int(a) for a in value.strip('[]').split(',')]
else:
raise ValueError()
for v in loop:
if not (7 >= v >= 1):
raise ValueError()
except (TypeError, ValueError):
raise ValidationError(
_("Enter a list if coma-separated values between 1 and 7."),
code='invalid')
# endregion - Validator -
default_validators = [ListBetween1And7Validator()]