mirror of
https://github.com/django/django.git
synced 2025-07-05 18:29:11 +00:00
queryset-refactor: Fixed up OneToOneFields (mostly).
They now share as much code as possible with ForeignKeys, but behave more or less as they did before (the backwards incompatible change is that they are no longer automatically primary keys -- so more than one per model is permitted). The documentation still uses an example that is better suited to model inheritance, but that will change in due course. Also, the admin interface still shows them as read-only fields, which is probably wrong now, but that can change on newforms-admin after this branch is merged into trunk. git-svn-id: http://code.djangoproject.com/svn/django/branches/queryset-refactor@7096 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
55cd025670
commit
accc20d799
@ -459,13 +459,69 @@ class ReverseManyRelatedObjectsDescriptor(object):
|
||||
manager.clear()
|
||||
manager.add(*value)
|
||||
|
||||
class ManyToOneRel(object):
|
||||
def __init__(self, to, field_name, num_in_admin=3, min_num_in_admin=None,
|
||||
max_num_in_admin=None, num_extra_on_change=1, edit_inline=False,
|
||||
related_name=None, limit_choices_to=None, lookup_overrides=None, raw_id_admin=False):
|
||||
try:
|
||||
to._meta
|
||||
except AttributeError: # to._meta doesn't exist, so it must be RECURSIVE_RELATIONSHIP_CONSTANT
|
||||
assert isinstance(to, basestring), "'to' must be either a model, a model name or the string %r" % RECURSIVE_RELATIONSHIP_CONSTANT
|
||||
self.to, self.field_name = to, field_name
|
||||
self.num_in_admin, self.edit_inline = num_in_admin, edit_inline
|
||||
self.min_num_in_admin, self.max_num_in_admin = min_num_in_admin, max_num_in_admin
|
||||
self.num_extra_on_change, self.related_name = num_extra_on_change, related_name
|
||||
if limit_choices_to is None:
|
||||
limit_choices_to = {}
|
||||
self.limit_choices_to = limit_choices_to
|
||||
self.lookup_overrides = lookup_overrides or {}
|
||||
self.raw_id_admin = raw_id_admin
|
||||
self.multiple = True
|
||||
|
||||
def get_related_field(self):
|
||||
"""
|
||||
Returns the Field in the 'to' object to which this relationship is
|
||||
tied.
|
||||
"""
|
||||
return self.to._meta.get_field_by_name(self.field_name, True)[0]
|
||||
|
||||
class OneToOneRel(ManyToOneRel):
|
||||
def __init__(self, to, field_name, num_in_admin=0, min_num_in_admin=None,
|
||||
max_num_in_admin=None, num_extra_on_change=None, edit_inline=False,
|
||||
related_name=None, limit_choices_to=None, lookup_overrides=None,
|
||||
raw_id_admin=False):
|
||||
# NOTE: *_num_in_admin and num_extra_on_change are intentionally
|
||||
# ignored here. We accept them as parameters only to match the calling
|
||||
# signature of ManyToOneRel.__init__().
|
||||
super(OneToOneRel, self).__init__(to, field_name, num_in_admin,
|
||||
edit_inline, related_name, limit_choices_to, lookup_overrides,
|
||||
raw_id_admin)
|
||||
self.multiple = False
|
||||
|
||||
class ManyToManyRel(object):
|
||||
def __init__(self, to, num_in_admin=0, related_name=None,
|
||||
filter_interface=None, limit_choices_to=None, raw_id_admin=False, symmetrical=True):
|
||||
self.to = to
|
||||
self.num_in_admin = num_in_admin
|
||||
self.related_name = related_name
|
||||
self.filter_interface = filter_interface
|
||||
if limit_choices_to is None:
|
||||
limit_choices_to = {}
|
||||
self.limit_choices_to = limit_choices_to
|
||||
self.edit_inline = False
|
||||
self.raw_id_admin = raw_id_admin
|
||||
self.symmetrical = symmetrical
|
||||
self.multiple = True
|
||||
|
||||
assert not (self.raw_id_admin and self.filter_interface), "ManyToManyRels may not use both raw_id_admin and filter_interface"
|
||||
|
||||
class ForeignKey(RelatedField, Field):
|
||||
empty_strings_allowed = False
|
||||
def __init__(self, to, to_field=None, **kwargs):
|
||||
def __init__(self, to, to_field=None, rel_class=ManyToOneRel, **kwargs):
|
||||
try:
|
||||
to_name = to._meta.object_name.lower()
|
||||
except AttributeError: # to._meta doesn't exist, so it must be RECURSIVE_RELATIONSHIP_CONSTANT
|
||||
assert isinstance(to, basestring), "ForeignKey(%r) is invalid. First parameter to ForeignKey must be either a model, a model name, or the string %r" % (to, RECURSIVE_RELATIONSHIP_CONSTANT)
|
||||
assert isinstance(to, basestring), "%s(%r) is invalid. First parameter to ForeignKey must be either a model, a model name, or the string %r" % (self.__class__.__name__, to, RECURSIVE_RELATIONSHIP_CONSTANT)
|
||||
else:
|
||||
to_field = to_field or to._meta.pk.name
|
||||
kwargs['verbose_name'] = kwargs.get('verbose_name', '')
|
||||
@ -475,7 +531,7 @@ class ForeignKey(RelatedField, Field):
|
||||
warnings.warn("edit_inline_type is deprecated. Use edit_inline instead.")
|
||||
kwargs['edit_inline'] = kwargs.pop('edit_inline_type')
|
||||
|
||||
kwargs['rel'] = ManyToOneRel(to, to_field,
|
||||
kwargs['rel'] = rel_class(to, to_field,
|
||||
num_in_admin=kwargs.pop('num_in_admin', 3),
|
||||
min_num_in_admin=kwargs.pop('min_num_in_admin', None),
|
||||
max_num_in_admin=kwargs.pop('max_num_in_admin', None),
|
||||
@ -563,82 +619,25 @@ class ForeignKey(RelatedField, Field):
|
||||
return IntegerField().db_type()
|
||||
return rel_field.db_type()
|
||||
|
||||
class OneToOneField(RelatedField, IntegerField):
|
||||
class OneToOneField(ForeignKey):
|
||||
"""
|
||||
A OneToOneField is essentially the same as a ForeignKey, with the exception
|
||||
that always carries a "unique" constraint with it and the reverse relation
|
||||
always returns the object pointed to (since there will only ever be one),
|
||||
rather than returning a list.
|
||||
"""
|
||||
def __init__(self, to, to_field=None, **kwargs):
|
||||
try:
|
||||
to_name = to._meta.object_name.lower()
|
||||
except AttributeError: # to._meta doesn't exist, so it must be RECURSIVE_RELATIONSHIP_CONSTANT
|
||||
assert isinstance(to, basestring), "OneToOneField(%r) is invalid. First parameter to OneToOneField must be either a model, a model name, or the string %r" % (to, RECURSIVE_RELATIONSHIP_CONSTANT)
|
||||
else:
|
||||
to_field = to_field or to._meta.pk.name
|
||||
kwargs['verbose_name'] = kwargs.get('verbose_name', '')
|
||||
|
||||
if 'edit_inline_type' in kwargs:
|
||||
import warnings
|
||||
warnings.warn("edit_inline_type is deprecated. Use edit_inline instead.")
|
||||
kwargs['edit_inline'] = kwargs.pop('edit_inline_type')
|
||||
|
||||
kwargs['rel'] = OneToOneRel(to, to_field,
|
||||
num_in_admin=kwargs.pop('num_in_admin', 0),
|
||||
edit_inline=kwargs.pop('edit_inline', False),
|
||||
related_name=kwargs.pop('related_name', None),
|
||||
limit_choices_to=kwargs.pop('limit_choices_to', None),
|
||||
lookup_overrides=kwargs.pop('lookup_overrides', None),
|
||||
raw_id_admin=kwargs.pop('raw_id_admin', False))
|
||||
kwargs['primary_key'] = True
|
||||
IntegerField.__init__(self, **kwargs)
|
||||
|
||||
self.db_index = True
|
||||
|
||||
def get_attname(self):
|
||||
return '%s_id' % self.name
|
||||
|
||||
def get_validator_unique_lookup_type(self):
|
||||
return '%s__%s__exact' % (self.name, self.rel.get_related_field().name)
|
||||
|
||||
# TODO: Copied from ForeignKey... putting this in RelatedField adversely affects
|
||||
# ManyToManyField. This works for now.
|
||||
def prepare_field_objs_and_params(self, manipulator, name_prefix):
|
||||
params = {'validator_list': self.validator_list[:], 'member_name': name_prefix + self.attname}
|
||||
if self.rel.raw_id_admin:
|
||||
field_objs = self.get_manipulator_field_objs()
|
||||
params['validator_list'].append(curry(manipulator_valid_rel_key, self, manipulator))
|
||||
else:
|
||||
if self.radio_admin:
|
||||
field_objs = [oldforms.RadioSelectField]
|
||||
params['ul_class'] = get_ul_class(self.radio_admin)
|
||||
else:
|
||||
if self.null:
|
||||
field_objs = [oldforms.NullSelectField]
|
||||
else:
|
||||
field_objs = [oldforms.SelectField]
|
||||
params['choices'] = self.get_choices_default()
|
||||
return field_objs, params
|
||||
|
||||
def contribute_to_class(self, cls, name):
|
||||
super(OneToOneField, self).contribute_to_class(cls, name)
|
||||
setattr(cls, self.name, ReverseSingleRelatedObjectDescriptor(self))
|
||||
kwargs['unique'] = True
|
||||
if 'num_in_admin' not in kwargs:
|
||||
kwargs['num_in_admin'] = 0
|
||||
super(OneToOneField, self).__init__(to, to_field, OneToOneRel, **kwargs)
|
||||
|
||||
def contribute_to_related_class(self, cls, related):
|
||||
setattr(cls, related.get_accessor_name(), SingleRelatedObjectDescriptor(related))
|
||||
setattr(cls, related.get_accessor_name(),
|
||||
SingleRelatedObjectDescriptor(related))
|
||||
if not cls._meta.one_to_one_field:
|
||||
cls._meta.one_to_one_field = self
|
||||
|
||||
def formfield(self, **kwargs):
|
||||
defaults = {'form_class': forms.ModelChoiceField, 'queryset': self.rel.to._default_manager.all()}
|
||||
defaults.update(kwargs)
|
||||
return super(OneToOneField, self).formfield(**defaults)
|
||||
|
||||
def db_type(self):
|
||||
# The database column type of a OneToOneField is the column type
|
||||
# of the field to which it points. An exception is if the OneToOneField
|
||||
# points to an AutoField/PositiveIntegerField/PositiveSmallIntegerField,
|
||||
# in which case the column type is simply that of an IntegerField.
|
||||
rel_field = self.rel.get_related_field()
|
||||
if isinstance(rel_field, (AutoField, PositiveIntegerField, PositiveSmallIntegerField)):
|
||||
return IntegerField().db_type()
|
||||
return rel_field.db_type()
|
||||
|
||||
class ManyToManyField(RelatedField, Field):
|
||||
def __init__(self, to, **kwargs):
|
||||
kwargs['verbose_name'] = kwargs.get('verbose_name', None)
|
||||
@ -770,59 +769,3 @@ class ManyToManyField(RelatedField, Field):
|
||||
# so return None.
|
||||
return None
|
||||
|
||||
class ManyToOneRel(object):
|
||||
def __init__(self, to, field_name, num_in_admin=3, min_num_in_admin=None,
|
||||
max_num_in_admin=None, num_extra_on_change=1, edit_inline=False,
|
||||
related_name=None, limit_choices_to=None, lookup_overrides=None, raw_id_admin=False):
|
||||
try:
|
||||
to._meta
|
||||
except AttributeError: # to._meta doesn't exist, so it must be RECURSIVE_RELATIONSHIP_CONSTANT
|
||||
assert isinstance(to, basestring), "'to' must be either a model, a model name or the string %r" % RECURSIVE_RELATIONSHIP_CONSTANT
|
||||
self.to, self.field_name = to, field_name
|
||||
self.num_in_admin, self.edit_inline = num_in_admin, edit_inline
|
||||
self.min_num_in_admin, self.max_num_in_admin = min_num_in_admin, max_num_in_admin
|
||||
self.num_extra_on_change, self.related_name = num_extra_on_change, related_name
|
||||
if limit_choices_to is None:
|
||||
limit_choices_to = {}
|
||||
self.limit_choices_to = limit_choices_to
|
||||
self.lookup_overrides = lookup_overrides or {}
|
||||
self.raw_id_admin = raw_id_admin
|
||||
self.multiple = True
|
||||
|
||||
def get_related_field(self):
|
||||
"""
|
||||
Returns the Field in the 'to' object to which this relationship is
|
||||
tied.
|
||||
"""
|
||||
return self.to._meta.get_field_by_name(self.field_name, True)[0]
|
||||
|
||||
class OneToOneRel(ManyToOneRel):
|
||||
def __init__(self, to, field_name, num_in_admin=0, edit_inline=False,
|
||||
related_name=None, limit_choices_to=None, lookup_overrides=None,
|
||||
raw_id_admin=False):
|
||||
self.to, self.field_name = to, field_name
|
||||
self.num_in_admin, self.edit_inline = num_in_admin, edit_inline
|
||||
self.related_name = related_name
|
||||
if limit_choices_to is None:
|
||||
limit_choices_to = {}
|
||||
self.limit_choices_to = limit_choices_to
|
||||
self.lookup_overrides = lookup_overrides or {}
|
||||
self.raw_id_admin = raw_id_admin
|
||||
self.multiple = False
|
||||
|
||||
class ManyToManyRel(object):
|
||||
def __init__(self, to, num_in_admin=0, related_name=None,
|
||||
filter_interface=None, limit_choices_to=None, raw_id_admin=False, symmetrical=True):
|
||||
self.to = to
|
||||
self.num_in_admin = num_in_admin
|
||||
self.related_name = related_name
|
||||
self.filter_interface = filter_interface
|
||||
if limit_choices_to is None:
|
||||
limit_choices_to = {}
|
||||
self.limit_choices_to = limit_choices_to
|
||||
self.edit_inline = False
|
||||
self.raw_id_admin = raw_id_admin
|
||||
self.symmetrical = symmetrical
|
||||
self.multiple = True
|
||||
|
||||
assert not (self.raw_id_admin and self.filter_interface), "ManyToManyRels may not use both raw_id_admin and filter_interface"
|
||||
|
@ -979,9 +979,6 @@ the relationship should work. All are optional:
|
||||
One-to-one relationships
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The semantics of one-to-one relationships will be changing soon, so we don't
|
||||
recommend you use them. If that doesn't scare you away, keep reading.
|
||||
|
||||
To define a one-to-one relationship, use ``OneToOneField``. You use it just
|
||||
like any other ``Field`` type: by including it as a class attribute of your
|
||||
model.
|
||||
@ -1003,9 +1000,11 @@ As with ``ForeignKey``, a relationship to self can be defined by using the
|
||||
string ``"self"`` instead of the model name; references to as-yet undefined
|
||||
models can be made by using a string containing the model name.
|
||||
|
||||
This ``OneToOneField`` will actually replace the primary key ``id`` field
|
||||
(since one-to-one relations share the same primary key), and will be displayed
|
||||
as a read-only field when you edit an object in the admin interface:
|
||||
**New in Django development version:** ``OneToOneField`` classes used to
|
||||
automatically become the primary key on a model. This is no longer true,
|
||||
although you can manually pass in the ``primary_key`` attribute if you like.
|
||||
Thus, it's now possible to have multilpe fields of type ``OneToOneField`` on a
|
||||
single model.
|
||||
|
||||
See the `One-to-one relationship model example`_ for a full example.
|
||||
|
||||
|
@ -16,7 +16,7 @@ class Place(models.Model):
|
||||
return u"%s the place" % self.name
|
||||
|
||||
class Restaurant(models.Model):
|
||||
place = models.OneToOneField(Place)
|
||||
place = models.OneToOneField(Place, primary_key=True)
|
||||
serves_hot_dogs = models.BooleanField()
|
||||
serves_pizza = models.BooleanField()
|
||||
|
||||
@ -38,6 +38,14 @@ class RelatedModel(models.Model):
|
||||
link = models.OneToOneField(ManualPrimaryKey)
|
||||
name = models.CharField(max_length = 50)
|
||||
|
||||
class MultiModel(models.Model):
|
||||
link1 = models.OneToOneField(Place)
|
||||
link2 = models.OneToOneField(ManualPrimaryKey)
|
||||
name = models.CharField(max_length=50)
|
||||
|
||||
def __unicode__(self):
|
||||
return u"Multimodel %s" % self.name
|
||||
|
||||
__test__ = {'API_TESTS':"""
|
||||
# Create a couple of Places.
|
||||
>>> p1 = Place(name='Demon Dogs', address='944 W. Fullerton')
|
||||
@ -63,8 +71,8 @@ Traceback (most recent call last):
|
||||
...
|
||||
DoesNotExist: Restaurant matching query does not exist.
|
||||
|
||||
# Set the place using assignment notation. Because place is the primary key on Restaurant,
|
||||
# the save will create a new restaurant
|
||||
# Set the place using assignment notation. Because place is the primary key on
|
||||
# Restaurant, the save will create a new restaurant
|
||||
>>> r.place = p2
|
||||
>>> r.save()
|
||||
>>> p2.restaurant
|
||||
@ -72,9 +80,9 @@ DoesNotExist: Restaurant matching query does not exist.
|
||||
>>> r.place
|
||||
<Place: Ace Hardware the place>
|
||||
|
||||
# Set the place back again, using assignment in the reverse direction
|
||||
# Need to reget restaurant object first, because the reverse set
|
||||
# can't update the existing restaurant instance
|
||||
# Set the place back again, using assignment in the reverse direction.
|
||||
# Need to reget restaurant object first, because the reverse set can't update
|
||||
# the existing restaurant instance
|
||||
>>> p1.restaurant = r
|
||||
>>> r.save()
|
||||
>>> p1.restaurant
|
||||
@ -86,8 +94,7 @@ DoesNotExist: Restaurant matching query does not exist.
|
||||
|
||||
# Restaurant.objects.all() just returns the Restaurants, not the Places.
|
||||
# Note that there are two restaurants - Ace Hardware the Restaurant was created
|
||||
# in the call to r.place = p2. This means there are multiple restaurants referencing
|
||||
# a single place...
|
||||
# in the call to r.place = p2.
|
||||
>>> Restaurant.objects.all()
|
||||
[<Restaurant: Demon Dogs the restaurant>, <Restaurant: Ace Hardware the restaurant>]
|
||||
|
||||
@ -165,4 +172,17 @@ DoesNotExist: Restaurant matching query does not exist.
|
||||
>>> o1.save()
|
||||
>>> o2 = RelatedModel(link=o1, name="secondary")
|
||||
>>> o2.save()
|
||||
|
||||
# You can have multiple one-to-one fields on a model, too.
|
||||
>>> x1 = MultiModel(link1=p1, link2=o1, name="x1")
|
||||
>>> x1.save()
|
||||
>>> o1.multimodel
|
||||
<MultiModel: Multimodel x1>
|
||||
|
||||
# This will fail because each one-to-one field must be unique (and link2=o1 was
|
||||
# used for x1, above).
|
||||
>>> MultiModel(link1=p2, link2=o1, name="x1").save()
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
IntegrityError: ...
|
||||
"""}
|
||||
|
@ -22,7 +22,7 @@ class Author(models.Model):
|
||||
|
||||
class Meta:
|
||||
ordering = ('name',)
|
||||
|
||||
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
@ -39,21 +39,21 @@ class Article(models.Model):
|
||||
return self.headline
|
||||
|
||||
class AuthorProfile(models.Model):
|
||||
author = models.OneToOneField(Author)
|
||||
author = models.OneToOneField(Author, primary_key=True)
|
||||
date_of_birth = models.DateField()
|
||||
|
||||
|
||||
def __unicode__(self):
|
||||
return u"Profile of %s" % self.author
|
||||
|
||||
|
||||
class Actor(models.Model):
|
||||
name = models.CharField(max_length=20, primary_key=True)
|
||||
|
||||
class Meta:
|
||||
ordering = ('name',)
|
||||
|
||||
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
class Movie(models.Model):
|
||||
actor = models.ForeignKey(Actor)
|
||||
title = models.CharField(max_length=50)
|
||||
@ -63,7 +63,7 @@ class Movie(models.Model):
|
||||
|
||||
def __unicode__(self):
|
||||
return self.title
|
||||
|
||||
|
||||
class Score(models.Model):
|
||||
score = models.FloatField()
|
||||
|
||||
@ -100,7 +100,7 @@ __test__ = {'API_TESTS':"""
|
||||
>>> dom = minidom.parseString(xml)
|
||||
|
||||
# Deserializing has a similar interface, except that special DeserializedObject
|
||||
# instances are returned. This is because data might have changed in the
|
||||
# instances are returned. This is because data might have changed in the
|
||||
# database since the data was serialized (we'll simulate that below).
|
||||
>>> for obj in serializers.deserialize("xml", xml):
|
||||
... print obj
|
||||
@ -148,7 +148,7 @@ __test__ = {'API_TESTS':"""
|
||||
>>> Article.objects.all()
|
||||
[<Article: Just kidding; I love TV poker>, <Article: Time to reform copyright>]
|
||||
|
||||
# If you use your own primary key field (such as a OneToOneField),
|
||||
# If you use your own primary key field (such as a OneToOneField),
|
||||
# it doesn't appear in the serialized field list - it replaces the
|
||||
# pk identifier.
|
||||
>>> profile = AuthorProfile(author=joe, date_of_birth=datetime(1970,1,1))
|
||||
@ -186,7 +186,7 @@ __test__ = {'API_TESTS':"""
|
||||
>>> print serializers.serialize("json", Article.objects.all(), fields=('headline','pub_date'))
|
||||
[{"pk": 1, "model": "serializers.article", "fields": {"headline": "Just kidding; I love TV poker", "pub_date": "2006-06-16 11:00:00"}}, {"pk": 2, "model": "serializers.article", "fields": {"headline": "Time to reform copyright", "pub_date": "2006-06-16 13:00:11"}}, {"pk": 3, "model": "serializers.article", "fields": {"headline": "Forward references pose no problem", "pub_date": "2006-06-16 15:00:00"}}]
|
||||
|
||||
# Every string is serialized as a unicode object, also primary key
|
||||
# Every string is serialized as a unicode object, also primary key
|
||||
# which is 'varchar'
|
||||
>>> ac = Actor(name="Zażółć")
|
||||
>>> mv = Movie(title="Gęślą jaźń", actor=ac)
|
||||
@ -247,12 +247,12 @@ try:
|
||||
pk: 2
|
||||
<BLANKLINE>
|
||||
|
||||
>>> obs = list(serializers.deserialize("yaml", serialized))
|
||||
>>> for i in obs:
|
||||
>>> obs = list(serializers.deserialize("yaml", serialized))
|
||||
>>> for i in obs:
|
||||
... print i
|
||||
<DeserializedObject: Just kidding; I love TV poker>
|
||||
<DeserializedObject: Time to reform copyright>
|
||||
|
||||
"""
|
||||
except ImportError: pass
|
||||
|
||||
|
||||
|
@ -77,7 +77,7 @@ class USStateData(models.Model):
|
||||
|
||||
class XMLData(models.Model):
|
||||
data = models.XMLField(null=True)
|
||||
|
||||
|
||||
class Tag(models.Model):
|
||||
"""A tag on an item."""
|
||||
data = models.SlugField()
|
||||
@ -93,36 +93,36 @@ class GenericData(models.Model):
|
||||
data = models.CharField(max_length=30)
|
||||
|
||||
tags = generic.GenericRelation(Tag)
|
||||
|
||||
|
||||
# The following test classes are all for validation
|
||||
# of related objects; in particular, forward, backward,
|
||||
# and self references.
|
||||
|
||||
|
||||
class Anchor(models.Model):
|
||||
"""This is a model that can be used as
|
||||
"""This is a model that can be used as
|
||||
something for other models to point at"""
|
||||
|
||||
|
||||
data = models.CharField(max_length=30)
|
||||
|
||||
class UniqueAnchor(models.Model):
|
||||
"""This is a model that can be used as
|
||||
"""This is a model that can be used as
|
||||
something for other models to point at"""
|
||||
|
||||
data = models.CharField(unique=True, max_length=30)
|
||||
|
||||
|
||||
class FKData(models.Model):
|
||||
data = models.ForeignKey(Anchor, null=True)
|
||||
|
||||
|
||||
class M2MData(models.Model):
|
||||
data = models.ManyToManyField(Anchor, null=True)
|
||||
|
||||
|
||||
class O2OData(models.Model):
|
||||
# One to one field can't be null, since it is a PK.
|
||||
data = models.OneToOneField(Anchor)
|
||||
# One to one field can't be null here, since it is a PK.
|
||||
data = models.OneToOneField(Anchor, primary_key=True)
|
||||
|
||||
class FKSelfData(models.Model):
|
||||
data = models.ForeignKey('self', null=True)
|
||||
|
||||
|
||||
class M2MSelfData(models.Model):
|
||||
data = models.ManyToManyField('self', null=True, symmetrical=False)
|
||||
|
||||
@ -142,7 +142,7 @@ class FKDataToO2O(models.Model):
|
||||
|
||||
class BooleanPKData(models.Model):
|
||||
data = models.BooleanField(primary_key=True)
|
||||
|
||||
|
||||
class CharPKData(models.Model):
|
||||
data = models.CharField(max_length=30, primary_key=True)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user