====== Advanced Django ====== ===== Authentication ===== ==== Use of the user model ==== There is only one class in Django which is ''User'', different types of users are instances of this class with other special attributes set. \\ Main attributes are: username, password, email, first_name, and last_name. However, there are [[https://docs.djangoproject.com/en/dev/ref/contrib/auth/#django.contrib.auth.models.User|others]]. \\ User classes and helper methods reference: ''https://docs.djangoproject.com/en/dev/ref/contrib/auth/'' === User creation === Using ''create_user'' function: from django.contrib.auth.models import User user = User.objects.create_user('john', 'lennon@thebeatles.com', 'johnpassword') # At this point, user is a User object that has already been saved to the database. user.last_name = 'Lennon' user.save() === Change user password === To change user passwords we'll do: from django.contrib.auth.models import User u = User.objects.get(username='john') u.set_password('new password') u.save() === User authentication === User ''authenticate()'', it takes credentials from keyword arguments and returns a ''User'' object if they were valid, if not returns ''None''. from django.contrib.auth import authenticate user = authenticate(username='john', password='secret') if user is not None: if user.is_active: print("User is valid, active and authenticated") else: print("The password is valid, but the account has been disabled!") else: print("The username and password were incorrect.") When a request is done, it is provided a ''request.user'' attribute. If the current user has not logged in the attribute will be set to an instance of ''AnonymousUser'', otherwise it will be an instance of ''User''. However you can tell it using ''is_authenticated()'' method: if request.user.is_authenticated(): # Do something for authenticated users. else: # Do something for anonymous users. === Login and logout === To login a user: [[https://docs.djangoproject.com/en/dev/topics/auth/default/#django.contrib.auth.login]]. \\ To logout use the ''logout'' function: from django.contrib.auth import logout def logout_view(request): logout(request) # Redirect to a success page. ==== Authorization ==== ==== Customizing authorization ==== * [[https://docs.djangoproject.com/en/dev/topics/auth/customizing/]] ===== Signals ===== ==== Signals in Django ==== Django provides a way of intercept special notifications... * ''django.db.models.signals.pre_save'' & ''django.db.models.signals.post_save'', sent before or after a model’s save() method is called. * ''django.db.models.signals.pre_delete'' & ''django.db.models.signals.post_delete'', sent before or after a model’s delete() method or queryset’s delete() method is called. * ''django.db.models.signals.m2m_changed'', sent when a ManyToManyField on a model is changed. * ''django.core.signals.request_started'' & ''django.core.signals.request_finished'', sent when Django starts or finishes an HTTP request. There are [[https://docs.djangoproject.com/en/dev/ref/signals/|ohters]] like ''pre_init'', ''class_prepared'', ''pre_migrate'', ''pre_syncdb'', ''got_request_exception'', ''connection_created''... ==== Connecting signals ==== The way to intercept a signal is using the ''connect()'' function or the ''receiver()'' decorator: def my_callback(sender, **kwargs): print("Request finished!") # ....... from django.core.signals import request_finished request_finished.connect(my_callback) # ....... from django.core.signals import request_finished from django.dispatch import receiver @receiver(request_finished) def my_callback(sender, **kwargs): print("Request finished!") The function ''Signal.connect'' has the next argument: Signal.connect(receiver[, sender=None, weak=True, dispatch_uid=None]) Its arguments mean: * Receiver argument is a function defined as: ''def my_callback(sender, **kwargs)''. * Sender argument concretes a sender class. * Weak argument avoid Django storing signal handlers as weak references, which is done by default. Thus, if your receiver is a local function, it may be garbage collected. To prevent this, pass ''weak=False'' when you call the signal’s connect() method. * dispatch_uid, its an unique identifier for a signal receiver in cases where duplicate signals may be sent. from myapp.models import MyModel @receiver(pre_save, sender=MyModel) def my_handler(sender, **kwargs): ... request_finished.connect(my_callback, dispatch_uid="my_unique_identifier") ==== Defining and sending signals ==== Signals are ''django.dispatch.Signal([providing_args=list])'' instances. ''providing_args'' is a list of the names of arguments the signal will provide to listeners. To declare a ''pizza_done'' signal which provides receivers with toppics and size arguments: import django.dispatch pizza_done = django.dispatch.Signal(providing_args=["toppings", "size"]) To send a signal, call either ''Signal.send()'' or ''Signal.send_robust()''. Both return a list of tuple pairs ''[(receiver, response), ... ]''. They differ in how exceptions raised by receiver functions. ''send()'' does not catch any exceptions raised by receivers; it simply allows errors to propagate. Whereas ''send_robust()'' catches all errors derived from Python’s Exception class, and ensures all receivers are notified of the signal. class PizzaStore(object): ... def send_pizza(self, toppings, size): pizza_done.send(sender=self.__class__, toppings=toppings, size=size) To disconnect a receiver from a signal, call ''Signal.disconnect()''.