Fixed #3098 -- Added db_table parameter to m2m fields, allowing the specification of a custom table name for the m2m table. Thanks, Wolfram Kriesing.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@4429 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Russell Keith-Magee 2007-01-25 13:47:55 +00:00
parent 12ad69c0b4
commit 54feaca70f
3 changed files with 82 additions and 22 deletions

View File

@ -629,6 +629,7 @@ class ManyToManyField(RelatedField, Field):
limit_choices_to=kwargs.pop('limit_choices_to', None), limit_choices_to=kwargs.pop('limit_choices_to', None),
raw_id_admin=kwargs.pop('raw_id_admin', False), raw_id_admin=kwargs.pop('raw_id_admin', False),
symmetrical=kwargs.pop('symmetrical', True)) symmetrical=kwargs.pop('symmetrical', True))
self.db_table = kwargs.pop('db_table', None)
if kwargs["rel"].raw_id_admin: if kwargs["rel"].raw_id_admin:
kwargs.setdefault("validator_list", []).append(self.isValidIDList) kwargs.setdefault("validator_list", []).append(self.isValidIDList)
Field.__init__(self, **kwargs) Field.__init__(self, **kwargs)
@ -651,6 +652,9 @@ class ManyToManyField(RelatedField, Field):
def _get_m2m_db_table(self, opts): def _get_m2m_db_table(self, opts):
"Function that can be curried to provide the m2m table name for this relation" "Function that can be curried to provide the m2m table name for this relation"
if self.db_table:
return self.db_table
else:
return '%s_%s' % (opts.db_table, self.name) return '%s_%s' % (opts.db_table, self.name)
def _get_m2m_column_name(self, related): def _get_m2m_column_name(self, related):

View File

@ -875,6 +875,10 @@ the relationship should work. All are optional:
relationship, allowing ``ManyToMany`` relationships to be relationship, allowing ``ManyToMany`` relationships to be
non-symmetrical. non-symmetrical.
``db_table`` The name of the table to create for storing the many-to-many
data. If this is not provided, Django will assume a default
name based upon the names of the two tables being joined.
======================= ============================================================ ======================= ============================================================
One-to-one relationships One-to-one relationships

View File

@ -1,53 +1,105 @@
""" """
17. Custom column names 17. Custom column/table names
If your database column name is different than your model attribute, use the If your database column name is different than your model attribute, use the
``db_column`` parameter. Note that you'll use the field's name, not its column ``db_column`` parameter. Note that you'll use the field's name, not its column
name, in API usage. name, in API usage.
If your database table name is different than your model name, use the
``db_table`` Meta attribute. This has no effect on the API used to
query the database.
If you need to use a table name for a many-to-many relationship that differs
from the default generated name, use the ``db_table`` parameter on the
ManyToMany field. This has no effect on the API for querying the database.
""" """
from django.db import models from django.db import models
class Person(models.Model): class Author(models.Model):
first_name = models.CharField(maxlength=30, db_column='firstname') first_name = models.CharField(maxlength=30, db_column='firstname')
last_name = models.CharField(maxlength=30, db_column='last') last_name = models.CharField(maxlength=30, db_column='last')
def __str__(self): def __str__(self):
return '%s %s' % (self.first_name, self.last_name) return '%s %s' % (self.first_name, self.last_name)
__test__ = {'API_TESTS':""" class Meta:
# Create a Person. db_table = 'my_author_table'
>>> p = Person(first_name='John', last_name='Smith') ordering = ('last_name','first_name')
>>> p.save()
>>> p.id class Article(models.Model):
headline = models.CharField(maxlength=100)
authors = models.ManyToManyField(Author, db_table='my_m2m_table')
def __str__(self):
return self.headline
class Meta:
ordering = ('headline',)
__test__ = {'API_TESTS':"""
# Create a Author.
>>> a = Author(first_name='John', last_name='Smith')
>>> a.save()
>>> a.id
1 1
>>> Person.objects.all() # Create another author
[<Person: John Smith>] >>> a2 = Author(first_name='Peter', last_name='Jones')
>>> a2.save()
>>> Person.objects.filter(first_name__exact='John') # Create an article
[<Person: John Smith>] >>> art = Article(headline='Django lets you build web apps easily')
>>> art.save()
>>> art.authors = [a, a2]
>>> Person.objects.get(first_name__exact='John') # Although the table and column names on Author have been set to
<Person: John Smith> # custom values, nothing about using the Author model has changed...
>>> Person.objects.filter(firstname__exact='John') # Query the available authors
>>> Author.objects.all()
[<Author: Peter Jones>, <Author: John Smith>]
>>> Author.objects.filter(first_name__exact='John')
[<Author: John Smith>]
>>> Author.objects.get(first_name__exact='John')
<Author: John Smith>
>>> Author.objects.filter(firstname__exact='John')
Traceback (most recent call last): Traceback (most recent call last):
... ...
TypeError: Cannot resolve keyword 'firstname' into field TypeError: Cannot resolve keyword 'firstname' into field
>>> p = Person.objects.get(last_name__exact='Smith') >>> a = Author.objects.get(last_name__exact='Smith')
>>> p.first_name >>> a.first_name
'John' 'John'
>>> p.last_name >>> a.last_name
'Smith' 'Smith'
>>> p.firstname >>> a.firstname
Traceback (most recent call last): Traceback (most recent call last):
... ...
AttributeError: 'Person' object has no attribute 'firstname' AttributeError: 'Author' object has no attribute 'firstname'
>>> p.last >>> a.last
Traceback (most recent call last): Traceback (most recent call last):
... ...
AttributeError: 'Person' object has no attribute 'last' AttributeError: 'Author' object has no attribute 'last'
# Although the Article table uses a custom m2m table,
# nothing about using the m2m relationship has changed...
# Get all the authors for an article
>>> art.authors.all()
[<Author: Peter Jones>, <Author: John Smith>]
# Get the articles for an author
>>> a.article_set.all()
[<Article: Django lets you build web apps easily>]
# Query the authors across the m2m relation
>>> art.authors.filter(last_name='Jones')
[<Author: Peter Jones>]
"""} """}