from django.db import models
class Address(models.Model):
address = models.CharField(max_length=255, blank=True)
city = models.CharField(max_length=150, blank=True)
state = models.CharField(max_length=2, blank=True)
zip = models.CharField(max_length=15, blank=True)
class Contact(models.Model):
first_name = models.CharField(max_length=255, blank=True)
last_name = models.CharField(max_length=255, blank=True)
birthdate = models.DateField(auto_now_add=True)
phone = models.CharField(max_length=25, blank=True)
email = models.EMailField(blank=True)
address = models.ForeignKey(Address, null=True)
nathan = Contact()
nathan.first_name = 'Nathan'
nathan.last_name = 'Yergler'
nathan.save()
.save()
only updates the fields that have changed..save()
updated the entire model, making it easy to overwrite changes.save()
behavior on its own)
.objects
QuerySet
API for convenienceContact.objects.filter(last_name__iexact='yergler')
Contact.objects.filter(address__state='OH')
models.Manager
to get queryset emulationclass ContactManager(models.Manager):
def with_email(self):
return self.filter(email__ne = '')
class Contact(models.Model):
...
objects = ContactManager()
contacts.objects.with_email().filter(email__endswith='osu.edu')
Manager.get_query_set()
allows you to customize the basic QuerySet used by Manager methodsdef test_with_email():
# make a couple Contacts
Contact.objects.create(first_name='Nathan')
Contact.objects.create(email='')
self.assertEqual(
len(Contact.objects.with_email()), 1
)
import factory
from models import Contact
class ContactFactory(factory.Factory):
FACTORY_FOR = Contact
first_name = 'John'
last_name = 'Doe'
# Returns a Contact instance that's not saved
contact = ContactFactory.build()
contact = ContactFactory.build(last_name='Yergler')
# Returns a saved Contact instance
contact = ContactFactory.create()
class AddressFactory(factory.Factory):
FACTORY_FOR = Address
contact = factory.SubFactory(ContactFactory)
address = AddressFactory(city='Columbus', state='OH')
address.contact.first_name
'John'
Contact.objects.filter(state='OH').filter(email__ne='')
If you need to do "or" conditions, you can use Q
objects
from django.db.models import Q
Contact.objects.filter(
Q(state='OH') | Q(email__endswith='osu.edu')
)
for user in Users.objects.filter(is_active=True):
send_email(user.email)
.values()
and .values_list()
avoid instantiationuser_emails = Users.objects.\
filter(is_active=True).\
values_list('email', flat=True)
for email in user_emails:
send_email(email)
select_related
queries for foreign keys in the initial queryContact.objects.\
select_related('address').\
filter(last_name = 'Yergler')
.raw()
method lets you do thisContact.objects.raw('SELECT * FROM contacts WHERE last_name = %s', [lname])
raw()
callsManagers have some additional helpers for operating on the table or collection:
get_or_create
update
delete
bulk_insert
MySQL's default transaction isolation for InnoDB breaks Django's get_or_create
when running at scale
def get_or_create(self, **kwargs):
try:
return self.get(**lookup), False
except self.model.DoesNotExist:
try:
obj = self.model(**params)
obj.save(force_insert=True, using=self.db)
return obj, True
except IntegrityError, e:
try:
return self.get(**lookup), False
except self.model.DoesNotExist:
raise e