2006-12-15 06:46:11 +01:00
|
|
|
"""
|
2007-12-02 20:29:54 +01:00
|
|
|
XX. Generating HTML forms from models
|
|
|
|
|
2008-08-12 16:15:38 +02:00
|
|
|
This is mostly just a reworking of the ``form_for_model``/``form_for_instance``
|
|
|
|
tests to use ``ModelForm``. As such, the text may not make sense in all cases,
|
|
|
|
and the examples are probably a poor fit for the ``ModelForm`` syntax. In other
|
|
|
|
words, most of these tests should be rewritten.
|
2006-12-15 06:46:11 +01:00
|
|
|
"""
|
2012-06-07 18:08:47 +02:00
|
|
|
from __future__ import unicode_literals
|
2006-12-15 06:46:11 +01:00
|
|
|
|
2014-02-01 20:23:31 +01:00
|
|
|
import datetime
|
2011-11-13 20:05:02 +01:00
|
|
|
import os
|
2008-01-17 19:03:21 +01:00
|
|
|
import tempfile
|
|
|
|
|
2013-06-05 20:55:05 +02:00
|
|
|
from django.core import validators
|
2013-08-05 21:26:51 +02:00
|
|
|
from django.core.exceptions import ImproperlyConfigured, ValidationError
|
2008-08-08 22:59:02 +02:00
|
|
|
from django.core.files.storage import FileSystemStorage
|
2011-10-13 20:04:12 +02:00
|
|
|
from django.db import models
|
2012-07-20 14:48:51 +02:00
|
|
|
from django.utils import six
|
2012-08-12 12:32:08 +02:00
|
|
|
from django.utils.encoding import python_2_unicode_compatible
|
2011-10-13 20:04:12 +02:00
|
|
|
|
2008-08-08 22:59:02 +02:00
|
|
|
|
2011-11-13 20:05:02 +01:00
|
|
|
temp_storage_dir = tempfile.mkdtemp(dir=os.environ['DJANGO_TEST_TEMP_DIR'])
|
2008-10-11 00:13:16 +02:00
|
|
|
temp_storage = FileSystemStorage(temp_storage_dir)
|
2006-12-15 06:46:11 +01:00
|
|
|
|
2007-04-28 16:18:03 +02:00
|
|
|
ARTICLE_STATUS = (
|
|
|
|
(1, 'Draft'),
|
|
|
|
(2, 'Pending'),
|
|
|
|
(3, 'Live'),
|
|
|
|
)
|
|
|
|
|
2008-08-31 22:11:11 +02:00
|
|
|
ARTICLE_STATUS_CHAR = (
|
|
|
|
('d', 'Draft'),
|
|
|
|
('p', 'Pending'),
|
|
|
|
('l', 'Live'),
|
|
|
|
)
|
|
|
|
|
2013-11-03 05:36:09 +01:00
|
|
|
|
2012-08-12 12:32:08 +02:00
|
|
|
@python_2_unicode_compatible
|
2006-12-15 06:46:11 +01:00
|
|
|
class Category(models.Model):
|
2007-08-05 07:14:46 +02:00
|
|
|
name = models.CharField(max_length=20)
|
2007-09-08 07:09:39 +02:00
|
|
|
slug = models.SlugField(max_length=20)
|
2007-08-05 07:14:46 +02:00
|
|
|
url = models.CharField('The URL', max_length=40)
|
2006-12-15 06:46:11 +01:00
|
|
|
|
2012-08-12 12:32:08 +02:00
|
|
|
def __str__(self):
|
2006-12-15 06:46:11 +01:00
|
|
|
return self.name
|
|
|
|
|
2012-08-14 23:38:35 +02:00
|
|
|
def __repr__(self):
|
|
|
|
return self.__str__()
|
|
|
|
|
2013-11-03 05:36:09 +01:00
|
|
|
|
2013-06-10 12:22:40 +02:00
|
|
|
@python_2_unicode_compatible
|
|
|
|
class Writer(models.Model):
|
|
|
|
name = models.CharField(max_length=50, help_text='Use both first and last names.')
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
ordering = ('name',)
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
return self.name
|
|
|
|
|
2013-11-03 05:36:09 +01:00
|
|
|
|
2012-08-12 12:32:08 +02:00
|
|
|
@python_2_unicode_compatible
|
2006-12-15 06:46:11 +01:00
|
|
|
class Article(models.Model):
|
2007-08-05 07:14:46 +02:00
|
|
|
headline = models.CharField(max_length=50)
|
2007-09-08 07:09:39 +02:00
|
|
|
slug = models.SlugField()
|
2006-12-30 01:12:02 +01:00
|
|
|
pub_date = models.DateField()
|
2007-02-20 03:59:16 +01:00
|
|
|
created = models.DateField(editable=False)
|
2013-06-10 12:22:40 +02:00
|
|
|
writer = models.ForeignKey(Writer)
|
2007-01-11 00:34:37 +01:00
|
|
|
article = models.TextField()
|
2006-12-28 03:34:53 +01:00
|
|
|
categories = models.ManyToManyField(Category, blank=True)
|
2008-09-01 21:20:03 +02:00
|
|
|
status = models.PositiveIntegerField(choices=ARTICLE_STATUS, blank=True, null=True)
|
2006-12-15 06:46:11 +01:00
|
|
|
|
2007-02-20 03:59:16 +01:00
|
|
|
def save(self):
|
|
|
|
if not self.id:
|
|
|
|
self.created = datetime.date.today()
|
|
|
|
return super(Article, self).save()
|
|
|
|
|
2012-08-12 12:32:08 +02:00
|
|
|
def __str__(self):
|
2006-12-15 06:46:11 +01:00
|
|
|
return self.headline
|
|
|
|
|
2013-11-03 05:36:09 +01:00
|
|
|
|
2008-08-22 21:27:26 +02:00
|
|
|
class ImprovedArticle(models.Model):
|
|
|
|
article = models.OneToOneField(Article)
|
|
|
|
|
2013-11-03 05:36:09 +01:00
|
|
|
|
2008-08-22 21:27:26 +02:00
|
|
|
class ImprovedArticleWithParentLink(models.Model):
|
|
|
|
article = models.OneToOneField(Article, parent_link=True)
|
|
|
|
|
2013-11-03 05:36:09 +01:00
|
|
|
|
2013-06-10 12:22:40 +02:00
|
|
|
class BetterWriter(Writer):
|
2010-01-05 04:56:19 +01:00
|
|
|
score = models.IntegerField()
|
2008-08-25 05:51:25 +02:00
|
|
|
|
2013-11-03 05:36:09 +01:00
|
|
|
|
2012-08-12 12:32:08 +02:00
|
|
|
@python_2_unicode_compatible
|
2013-06-10 12:22:40 +02:00
|
|
|
class WriterProfile(models.Model):
|
|
|
|
writer = models.OneToOneField(Writer, primary_key=True)
|
2008-08-31 11:49:55 +02:00
|
|
|
age = models.PositiveIntegerField()
|
2008-09-02 00:43:38 +02:00
|
|
|
|
2012-08-12 12:32:08 +02:00
|
|
|
def __str__(self):
|
2008-08-31 11:49:55 +02:00
|
|
|
return "%s is %s" % (self.writer, self.age)
|
|
|
|
|
2013-11-03 05:36:09 +01:00
|
|
|
|
2012-08-12 12:32:08 +02:00
|
|
|
@python_2_unicode_compatible
|
2008-01-17 19:03:21 +01:00
|
|
|
class TextFile(models.Model):
|
|
|
|
description = models.CharField(max_length=20)
|
2009-03-31 00:52:16 +02:00
|
|
|
file = models.FileField(storage=temp_storage, upload_to='tests', max_length=15)
|
2008-01-17 19:03:21 +01:00
|
|
|
|
2012-08-12 12:32:08 +02:00
|
|
|
def __str__(self):
|
2008-01-17 19:03:21 +01:00
|
|
|
return self.description
|
2008-02-14 13:56:49 +01:00
|
|
|
|
2009-02-16 19:34:28 +01:00
|
|
|
try:
|
2013-10-18 13:25:30 +02:00
|
|
|
from django.utils.image import Image # NOQA: detect if Pillow is installed
|
2010-03-16 20:32:11 +01:00
|
|
|
|
2009-02-16 19:34:28 +01:00
|
|
|
test_images = True
|
2009-03-15 06:05:26 +01:00
|
|
|
|
2012-08-12 12:32:08 +02:00
|
|
|
@python_2_unicode_compatible
|
2009-02-16 19:34:28 +01:00
|
|
|
class ImageFile(models.Model):
|
|
|
|
def custom_upload_path(self, filename):
|
|
|
|
path = self.path or 'tests'
|
|
|
|
return '%s/%s' % (path, filename)
|
2009-03-15 06:05:26 +01:00
|
|
|
|
2009-02-16 19:34:28 +01:00
|
|
|
description = models.CharField(max_length=20)
|
2009-05-11 11:57:19 +02:00
|
|
|
|
|
|
|
# Deliberately put the image field *after* the width/height fields to
|
|
|
|
# trigger the bug in #10404 with width/height not getting assigned.
|
2009-02-16 19:34:28 +01:00
|
|
|
width = models.IntegerField(editable=False)
|
|
|
|
height = models.IntegerField(editable=False)
|
2009-05-11 11:57:19 +02:00
|
|
|
image = models.ImageField(storage=temp_storage, upload_to=custom_upload_path,
|
|
|
|
width_field='width', height_field='height')
|
2009-02-16 19:34:28 +01:00
|
|
|
path = models.CharField(max_length=16, blank=True, default='')
|
|
|
|
|
2012-08-12 12:32:08 +02:00
|
|
|
def __str__(self):
|
2009-02-16 19:34:28 +01:00
|
|
|
return self.description
|
2009-03-15 06:05:26 +01:00
|
|
|
|
2012-08-12 12:32:08 +02:00
|
|
|
@python_2_unicode_compatible
|
2009-02-16 19:34:28 +01:00
|
|
|
class OptionalImageFile(models.Model):
|
|
|
|
def custom_upload_path(self, filename):
|
|
|
|
path = self.path or 'tests'
|
|
|
|
return '%s/%s' % (path, filename)
|
2009-03-15 06:05:26 +01:00
|
|
|
|
2009-02-16 19:34:28 +01:00
|
|
|
description = models.CharField(max_length=20)
|
|
|
|
image = models.ImageField(storage=temp_storage, upload_to=custom_upload_path,
|
2009-03-15 06:05:26 +01:00
|
|
|
width_field='width', height_field='height',
|
2009-02-16 19:34:28 +01:00
|
|
|
blank=True, null=True)
|
|
|
|
width = models.IntegerField(editable=False, null=True)
|
|
|
|
height = models.IntegerField(editable=False, null=True)
|
|
|
|
path = models.CharField(max_length=16, blank=True, default='')
|
|
|
|
|
2012-08-12 12:32:08 +02:00
|
|
|
def __str__(self):
|
2009-02-16 19:34:28 +01:00
|
|
|
return self.description
|
2013-05-15 04:31:16 +02:00
|
|
|
except ImproperlyConfigured:
|
2009-02-16 19:34:28 +01:00
|
|
|
test_images = False
|
2009-03-15 06:05:26 +01:00
|
|
|
|
2013-11-03 05:36:09 +01:00
|
|
|
|
2012-08-12 12:32:08 +02:00
|
|
|
@python_2_unicode_compatible
|
2008-08-28 22:58:10 +02:00
|
|
|
class CommaSeparatedInteger(models.Model):
|
|
|
|
field = models.CommaSeparatedIntegerField(max_length=20)
|
|
|
|
|
2012-08-12 12:32:08 +02:00
|
|
|
def __str__(self):
|
2008-08-28 22:58:10 +02:00
|
|
|
return self.field
|
|
|
|
|
2013-11-03 05:36:09 +01:00
|
|
|
|
2012-08-12 12:32:08 +02:00
|
|
|
@python_2_unicode_compatible
|
2008-09-01 21:08:08 +02:00
|
|
|
class Product(models.Model):
|
|
|
|
slug = models.SlugField(unique=True)
|
|
|
|
|
2012-08-12 12:32:08 +02:00
|
|
|
def __str__(self):
|
2008-09-01 21:08:08 +02:00
|
|
|
return self.slug
|
|
|
|
|
2013-11-03 05:36:09 +01:00
|
|
|
|
2012-08-12 12:32:08 +02:00
|
|
|
@python_2_unicode_compatible
|
2008-09-01 21:08:08 +02:00
|
|
|
class Price(models.Model):
|
|
|
|
price = models.DecimalField(max_digits=10, decimal_places=2)
|
|
|
|
quantity = models.PositiveIntegerField()
|
|
|
|
|
2012-08-12 12:32:08 +02:00
|
|
|
def __str__(self):
|
2012-06-07 18:08:47 +02:00
|
|
|
return "%s for %s" % (self.quantity, self.price)
|
2008-09-01 21:08:08 +02:00
|
|
|
|
|
|
|
class Meta:
|
|
|
|
unique_together = (('price', 'quantity'),)
|
|
|
|
|
2013-11-03 05:36:09 +01:00
|
|
|
|
2008-08-31 22:11:11 +02:00
|
|
|
class ArticleStatus(models.Model):
|
|
|
|
status = models.CharField(max_length=2, choices=ARTICLE_STATUS_CHAR, blank=True, null=True)
|
|
|
|
|
2013-11-03 05:36:09 +01:00
|
|
|
|
2012-08-12 12:32:08 +02:00
|
|
|
@python_2_unicode_compatible
|
2008-09-02 00:43:38 +02:00
|
|
|
class Inventory(models.Model):
|
2011-03-04 02:27:14 +01:00
|
|
|
barcode = models.PositiveIntegerField(unique=True)
|
|
|
|
parent = models.ForeignKey('self', to_field='barcode', blank=True, null=True)
|
|
|
|
name = models.CharField(blank=False, max_length=20)
|
2008-09-01 21:08:08 +02:00
|
|
|
|
2011-03-04 02:27:14 +01:00
|
|
|
class Meta:
|
|
|
|
ordering = ('name',)
|
|
|
|
|
2012-08-12 12:32:08 +02:00
|
|
|
def __str__(self):
|
2011-03-04 02:27:14 +01:00
|
|
|
return self.name
|
2008-10-21 16:04:24 +02:00
|
|
|
|
2012-08-14 23:38:35 +02:00
|
|
|
def __repr__(self):
|
|
|
|
return self.__str__()
|
|
|
|
|
2013-11-03 05:36:09 +01:00
|
|
|
|
2013-06-10 12:22:40 +02:00
|
|
|
class Book(models.Model):
|
|
|
|
title = models.CharField(max_length=40)
|
|
|
|
author = models.ForeignKey(Writer, blank=True, null=True)
|
|
|
|
special_id = models.IntegerField(blank=True, null=True, unique=True)
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
unique_together = ('title', 'author')
|
|
|
|
|
2013-11-03 05:36:09 +01:00
|
|
|
|
2010-03-16 20:32:11 +01:00
|
|
|
class BookXtra(models.Model):
|
|
|
|
isbn = models.CharField(max_length=16, unique=True)
|
|
|
|
suffix1 = models.IntegerField(blank=True, default=0)
|
|
|
|
suffix2 = models.IntegerField(blank=True, default=0)
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
unique_together = (('suffix1', 'suffix2'))
|
|
|
|
abstract = True
|
|
|
|
|
2013-11-03 05:36:09 +01:00
|
|
|
|
2010-03-16 20:32:11 +01:00
|
|
|
class DerivedBook(Book, BookXtra):
|
|
|
|
pass
|
|
|
|
|
2013-11-03 05:36:09 +01:00
|
|
|
|
2012-08-12 12:32:08 +02:00
|
|
|
@python_2_unicode_compatible
|
2008-11-05 20:47:44 +01:00
|
|
|
class ExplicitPK(models.Model):
|
|
|
|
key = models.CharField(max_length=20, primary_key=True)
|
|
|
|
desc = models.CharField(max_length=20, blank=True, unique=True)
|
2013-10-22 12:21:07 +02:00
|
|
|
|
2008-11-05 20:47:44 +01:00
|
|
|
class Meta:
|
|
|
|
unique_together = ('key', 'desc')
|
2009-03-15 06:05:26 +01:00
|
|
|
|
2012-08-12 12:32:08 +02:00
|
|
|
def __str__(self):
|
2008-11-05 20:47:44 +01:00
|
|
|
return self.key
|
2008-10-21 16:04:24 +02:00
|
|
|
|
2013-11-03 05:36:09 +01:00
|
|
|
|
2012-08-12 12:32:08 +02:00
|
|
|
@python_2_unicode_compatible
|
2009-04-30 15:47:39 +02:00
|
|
|
class Post(models.Model):
|
|
|
|
title = models.CharField(max_length=50, unique_for_date='posted', blank=True)
|
|
|
|
slug = models.CharField(max_length=50, unique_for_year='posted', blank=True)
|
|
|
|
subtitle = models.CharField(max_length=50, unique_for_month='posted', blank=True)
|
|
|
|
posted = models.DateField()
|
|
|
|
|
2012-08-12 12:32:08 +02:00
|
|
|
def __str__(self):
|
2013-05-28 15:56:14 +02:00
|
|
|
return self.title
|
|
|
|
|
2013-11-03 05:36:09 +01:00
|
|
|
|
2013-05-28 15:56:14 +02:00
|
|
|
@python_2_unicode_compatible
|
|
|
|
class DateTimePost(models.Model):
|
|
|
|
title = models.CharField(max_length=50, unique_for_date='posted', blank=True)
|
|
|
|
slug = models.CharField(max_length=50, unique_for_year='posted', blank=True)
|
|
|
|
subtitle = models.CharField(max_length=50, unique_for_month='posted', blank=True)
|
|
|
|
posted = models.DateTimeField(editable=False)
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
return self.title
|
2009-04-30 15:47:39 +02:00
|
|
|
|
2013-11-03 05:36:09 +01:00
|
|
|
|
2010-03-16 20:32:11 +01:00
|
|
|
class DerivedPost(Post):
|
|
|
|
pass
|
|
|
|
|
2013-11-03 05:36:09 +01:00
|
|
|
|
2012-08-12 12:32:08 +02:00
|
|
|
@python_2_unicode_compatible
|
2009-12-17 16:10:38 +01:00
|
|
|
class BigInt(models.Model):
|
|
|
|
biggie = models.BigIntegerField()
|
|
|
|
|
2012-08-12 12:32:08 +02:00
|
|
|
def __str__(self):
|
2012-07-20 14:48:51 +02:00
|
|
|
return six.text_type(self.biggie)
|
2009-12-17 16:10:38 +01:00
|
|
|
|
2013-11-03 05:36:09 +01:00
|
|
|
|
2010-03-31 09:43:52 +02:00
|
|
|
class MarkupField(models.CharField):
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
kwargs["max_length"] = 20
|
|
|
|
super(MarkupField, self).__init__(*args, **kwargs)
|
|
|
|
|
|
|
|
def formfield(self, **kwargs):
|
|
|
|
# don't allow this field to be used in form (real use-case might be
|
|
|
|
# that you know the markup will always be X, but it is among an app
|
|
|
|
# that allows the user to say it could be something else)
|
|
|
|
# regressed at r10062
|
|
|
|
return None
|
|
|
|
|
2013-11-03 05:36:09 +01:00
|
|
|
|
2010-03-31 09:43:52 +02:00
|
|
|
class CustomFieldForExclusionModel(models.Model):
|
|
|
|
name = models.CharField(max_length=10)
|
|
|
|
markup = MarkupField()
|
|
|
|
|
2013-11-03 05:36:09 +01:00
|
|
|
|
2011-01-09 14:26:39 +01:00
|
|
|
class FlexibleDatePost(models.Model):
|
|
|
|
title = models.CharField(max_length=50, unique_for_date='posted', blank=True)
|
|
|
|
slug = models.CharField(max_length=50, unique_for_year='posted', blank=True)
|
|
|
|
subtitle = models.CharField(max_length=50, unique_for_month='posted', blank=True)
|
2011-02-26 09:50:15 +01:00
|
|
|
posted = models.DateField(blank=True, null=True)
|
2012-12-19 19:12:08 +01:00
|
|
|
|
2013-11-03 05:36:09 +01:00
|
|
|
|
2012-12-19 19:12:08 +01:00
|
|
|
@python_2_unicode_compatible
|
|
|
|
class Colour(models.Model):
|
|
|
|
name = models.CharField(max_length=50)
|
|
|
|
|
|
|
|
def __iter__(self):
|
|
|
|
for number in xrange(5):
|
|
|
|
yield number
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
return self.name
|
|
|
|
|
2013-11-03 05:36:09 +01:00
|
|
|
|
2012-12-19 19:12:08 +01:00
|
|
|
class ColourfulItem(models.Model):
|
|
|
|
name = models.CharField(max_length=50)
|
|
|
|
colours = models.ManyToManyField(Colour)
|
2013-05-21 23:32:39 +02:00
|
|
|
|
2013-11-03 05:36:09 +01:00
|
|
|
|
2013-05-21 23:32:39 +02:00
|
|
|
class ArticleStatusNote(models.Model):
|
|
|
|
name = models.CharField(max_length=20)
|
|
|
|
status = models.ManyToManyField(ArticleStatus)
|
2013-06-05 20:55:05 +02:00
|
|
|
|
2013-11-03 05:36:09 +01:00
|
|
|
|
2013-06-05 20:55:05 +02:00
|
|
|
class CustomErrorMessage(models.Model):
|
|
|
|
name1 = models.CharField(max_length=50,
|
|
|
|
validators=[validators.validate_slug],
|
|
|
|
error_messages={'invalid': 'Model custom error message.'})
|
|
|
|
|
|
|
|
name2 = models.CharField(max_length=50,
|
|
|
|
validators=[validators.validate_slug],
|
|
|
|
error_messages={'invalid': 'Model custom error message.'})
|
2013-08-05 21:26:51 +02:00
|
|
|
|
|
|
|
def clean(self):
|
|
|
|
if self.name1 == 'FORBIDDEN_VALUE':
|
|
|
|
raise ValidationError({'name1': [ValidationError('Model.clean() error messages.')]})
|
2014-02-01 20:23:31 +01:00
|
|
|
|
|
|
|
|
|
|
|
def today_callable_dict():
|
|
|
|
return {"last_action__gte": datetime.datetime.today()}
|
|
|
|
|
|
|
|
|
|
|
|
def today_callable_q():
|
|
|
|
return models.Q(last_action__gte=datetime.datetime.today())
|
|
|
|
|
|
|
|
|
|
|
|
class Character(models.Model):
|
|
|
|
username = models.CharField(max_length=100)
|
|
|
|
last_action = models.DateTimeField()
|
|
|
|
|
|
|
|
|
|
|
|
class StumpJoke(models.Model):
|
|
|
|
most_recently_fooled = models.ForeignKey(Character, limit_choices_to=today_callable_dict, related_name="+")
|
|
|
|
has_fooled_today = models.ManyToManyField(Character, limit_choices_to=today_callable_q, related_name="+")
|