Single Email field in Django User model

3

I have a system that has a user registry and I'm using the lib django.contrib.auth.models to do this registration. But I I need the email field of this model to be unique.

from django.db import models
from django.contrib.auth.models import User

class CadastroUsuario(models.Model):
    user = models.ForeignKey(User)
    documento = models.CharField(max_length=250)

    def __unicode__(self):
        return self.user.email

Does anyone know how best to do this? I'm starting in Django and I'm having a hard time finding a solution.

I'm working with Django 1.4.7 on this project.

    
asked by anonymous 13.04.2015 / 20:29

1 answer

1

You are in the dark, as of version 1.5 you can use your own template to represent a user , but in 1.4 or below there is (as far as I know) a" clean "way to modify the User template. Unless you are willing to upgrade (and if you are, use a newer version, the 1.5 that I know has been discontinued for security reasons), you will need an alternate strategy.

>
  • You could change the table directly in the database, marking the column as UNIQUE ; as far as I know, this will not break the existing templates, but you'll have an exception if you try to register two users with the same email by ORM (and the treatment will be less smooth because your model still "thinks" that the field is not unique).

    • Advantage: no matter where the data comes from - inside or outside your system - the database will not let duplicate data come in.
    • Disadvantage (?): I do not know what undesirable effects can occur from the bank having one structure and the ORM having another (although essentially compatible). You will need to be aware of unexpected errors, and test the system very well in every situation involving the User model.
  • You can use the sign pre_save to detect when a user is about to be saved, and to do there the uniqueness check of the email field. I have no experience with signals, but the documentation suggests that it is simply a matter of defining a function as follows:

    from django.db.models.signals import pre_save
    from django.dispatch import receiver
    from django.contrib.auth.models import User
    
    @receiver(pre_save, sender=User)
    def my_handler(sender, **kwargs):
        ... # Aqui sender é o usuário sendo salvo
    
    • Disadvantage: If you create multiple objects in a single operation (eg bulk_create ) this signal will not be sent, and its function will not be called.
  • If you use admin , you can try customizing it to fit this additional constraint. The topic is extensive, and I do not have enough experience to cover all the possibilities here (customize the form , give a friendly message if the field value is invalid, etc.).

  • >
  • In your views , of course, you can give special treatment to this field. There are at least two ways (each within a transaction, of course):

    • Query to check if an email is being repeated, then insert / update the actual element (s):

      if not User.object.filter(email__in=lista_de_emails_a_inserir):
          ... # Insere o(s) novo(s) usuário(s)
      
    • Make the changes you want, and in the end check if any of them caused a duplicate email; if it provoked you, do rollback at all:

      ... # Insere o(s) novo(s) usuário(s)
      if User.objects.values('email').annotate(contagem=Count('email')).order_by().filter(contagem__gt=1):
          transaction.rollback()
      

      Font , explaining why this% empty% is required.

    Note that some solutions may treat competitors better than others, or perform better / worse.

  • You can create a order_by for each user, and in this template repeat the UserProfile field by placing it unique. The email is unique, so it does not have two users having the same profile.

    • Warning: I can not remember if it is possible to "force" all UserProfile to have a User - if any UserProfile ends without a User , this solution does not will ensure the uniqueness of the email.
  • Finally, you can try to make "monkey patch" in the UserProfile template, modifying its User field so that it is email . This is the most "extreme" solution, and I can not anticipate what kinds of problems you might encounter.

There may be other ways, but that's what came to mind. Note that some of these techniques can be used together, complementing each other (eg change the field in the database to ensure data integrity, and also change admin / views to ensure smooth handling of errors). >     

14.04.2015 / 07:45