diff options
Diffstat (limited to 'docs/model-api.txt')
-rw-r--r-- | docs/model-api.txt | 166 |
1 files changed, 155 insertions, 11 deletions
diff --git a/docs/model-api.txt b/docs/model-api.txt index 4975953b97..93b27b8c11 100644 --- a/docs/model-api.txt +++ b/docs/model-api.txt @@ -112,7 +112,7 @@ class. Django uses the field class types to determine a few things: * The widget to use in Django's admin interface, if you care to use it (e.g. ``<input type="text">``, ``<select>``). * The minimal validation requirements, used in Django's admin and in - manipulators. + automatically-generated forms. Here are all available field types: @@ -144,10 +144,6 @@ The admin represents this as an ``<input type="text">`` (a single-line input). (in characters) of the field. The max_length is enforced at the database level and in Django's validation. -Django veterans: Note that the argument is now called ``max_length`` to -provide consistency throughout Django. There is full legacy support for -the old ``maxlength`` argument, but ``max_length`` is preferred. - ``CommaSeparatedIntegerField`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -641,9 +637,8 @@ callable it will be called every time a new object is created. ``editable`` ~~~~~~~~~~~~ -If ``False``, the field will not be editable in the admin or via form -processing using the object's ``AddManipulator`` or ``ChangeManipulator`` -classes. Default is ``True``. +If ``False``, the field will not be editable in the admin or via forms +automatically generated from the model class. Default is ``True``. ``help_text`` ~~~~~~~~~~~~~ @@ -656,7 +651,10 @@ Note that this value is *not* HTML-escaped when it's displayed in the admin interface. This lets you include HTML in ``help_text`` if you so desire. For example:: - help_text="Please use the following format: <em>YYYY-MM-DD</em>." + help_text="Please use the following format: <em>YYYY-MM-DD</em>." + +Alternatively you can use plain text and +``django.utils.html.escape()`` to escape any HTML special characters. ``primary_key`` ~~~~~~~~~~~~~~~ @@ -716,7 +714,7 @@ that takes the parameters ``field_data, all_data`` and raises Django comes with quite a few validators. They're in ``django.core.validators``. -.. _validator docs: ../forms/#validators +.. _validator docs: ../oldforms/#validators Verbose field names ------------------- @@ -942,6 +940,139 @@ the relationship should work. All are optional: ======================= ============================================================ +Extra fields on many-to-many relationships +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**New in Django development version** + +When you're only dealing with simple many-to-many relationships such as +mixing and matching pizzas and toppings, a standard ``ManyToManyField`` +is all you need. However, sometimes you may need to associate data with the +relationship between two models. + +For example, consider the case of an application tracking the musical groups +which musicians belong to. There is a many-to-many relationship between a person +and the groups of which they are a member, so you could use a ManyToManyField +to represent this relationship. However, there is a lot of detail about the +membership that you might want to collect, such as the date at which the person +joined the group. + +For these situations, Django allows you to specify the model that will be used +to govern the many-to-many relationship. You can then put extra fields on the +intermediate model. The intermediate model is associated with the +``ManyToManyField`` using the ``through`` argument to point to the model +that will act as an intermediary. For our musician example, the code would look +something like this:: + + class Person(models.Model): + name = models.CharField(max_length=128) + + def __unicode__(self): + return self.name + + class Group(models.Model): + name = models.CharField(max_length=128) + members = models.ManyToManyField(Person, through='Membership') + + def __unicode__(self): + return self.name + + class Membership(models.Model): + person = models.ForeignKey(Person) + group = models.ForeignKey(Group) + date_joined = models.DateField() + invite_reason = models.CharField(max_length=64) + +When you set up the intermediary model, you explicitly specify foreign +keys to the models that are involved in the ManyToMany relation. This +explicit declaration defines how the two models are related. + +There are a few restrictions on the intermediate model: + + * Your intermediate model must contain one - and *only* one - foreign key + on the target model (this would be ``Person`` in our example). If you + have more than one foreign key, a validation error will be raised. + + * Your intermediate model must contain one - and *only* one - foreign key + on the source model (this would be ``Group`` in our example). If you + have more than one foreign key, a validation error will be raised. + + * The only exception to this is a model which has a many-to-many + relationship to itself, through an intermediary model. In this + case, two foreign keys to the same model are permitted, but they + will be treated as the two (different) sides of the many-to-many + relation. + + * When defining a many-to-many relationship from a model to + itself, using an intermediary model, you *must* use + ``symmetrical=False`` (see the documentation for + ``ManyToManyField`` above). + +Now that you have set up your ``ManyToManyField`` to use your intermediary +model (Membership, in this case), you're ready to start creating some +many-to-many relationships. You do this by creating instances of the +intermediate model:: + + >>> ringo = Person.objects.create(name="Ringo Starr") + >>> paul = Person.objects.create(name="Paul McCartney") + >>> beatles = Group.objects.create(name="The Beatles") + >>> m1 = Membership(person=ringo, group=beatles, + ... date_joined=date(1962, 8, 16), + ... invite_reason= "Needed a new drummer.") + >>> m1.save() + >>> beatles.members.all() + [<Person: Ringo Starr>] + >>> ringo.group_set.all() + [<Group: The Beatles>] + >>> m2 = Membership.objects.create(person=paul, group=beatles, + ... date_joined=date(1960, 8, 1), + ... invite_reason= "Wanted to form a band.") + >>> beatles.members.all() + [<Person: Ringo Starr>, <Person: Paul McCartney>] + +Unlike normal many-to-many fields, you *can't* use ``add``, ``create``, +or assignment (i.e., ``beatles.members = [...]``) to create relationships:: + + # THIS WILL NOT WORK + >>> beatles.members.add(john) + # NEITHER WILL THIS + >>> beatles.members.create(name="George Harrison") + # AND NEITHER WILL THIS + >>> beatles.members = [john, paul, ringo, george] + +Why? You can't just create a relationship between a Person and a Group - you +need to specify all the detail for the relationship required by the +Membership table. The simple ``add``, ``create`` and assignment calls +don't provide a way to specify this extra detail. As a result, they are +disabled for many-to-many relationships that use an intermediate model. +The only way to create a many-to-many relationship with an intermediate table +is to create instances of the intermediate model. + +The ``remove`` method is disabled for similar reasons. However, the +``clear()`` method can be used to remove all many-to-many relationships +for an instance:: + + # Beatles have broken up + >>> beatles.members.clear() + +Once you have established the many-to-many relationships by creating instances +of your intermediate model, you can issue queries. Just as with normal +many-to-many relationships, you can query using the attributes of the +many-to-many-related model:: + + # Find all the groups with a member whose name starts with 'Paul' + >>> Groups.objects.filter(person__name__startswith='Paul') + [<Group: The Beatles>] + +As you are using an intermediate table, you can also query on the attributes +of the intermediate model:: + + # Find all the members of the Beatles that joined after 1 Jan 1961 + >>> Person.objects.filter( + ... group__name='The Beatles', + ... membership__date_joined__gt=date(1961,1,1)) + [<Person: Ringo Starr] + One-to-one relationships ~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1143,7 +1274,7 @@ any parent classes in ``unique_together``. For convenience, unique_together can be a single list when dealing with a single set of fields:: - unique_together = ("driver", "restaurant") + unique_together = ("driver", "restaurant") ``verbose_name`` ---------------- @@ -1376,6 +1507,19 @@ good idea to be careful in your choice of default manager, in order to avoid a situation where overriding of ``get_query_set()`` results in an inability to retrieve objects you'd like to work with. +Using managers for related object access +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +By default, Django uses a "bare" (i.e. default) manager when accessing related +objects (i.e. ``choice.poll``). If this default isn't appropriate for your +default manager, you can force Django to use a custom manager for related object +attributes by giving it a ``use_for_related_fields`` property:: + + class MyManager(models.Manager):: + use_for_related_fields = True + + ... + Model methods ============= |