Django

Code

Ticket #87: fields.py

File fields.py, 30.9 kB (added by Jason Huggins, 5 years ago)
Line 
1 from django.conf import settings
2 from django.core import formfields, validators
3 from django.core import db
4 from django.core.exceptions import ObjectDoesNotExist
5 from django.utils.functional import curry
6 from django.utils.text import capfirst
7 import datetime, os
8
9 # Random entropy string used by "default" param.
10 NOT_PROVIDED = 'oijpwojefiojpanv'
11
12 # Values for filter_interface.
13 HORIZONTAL, VERTICAL = 1, 2
14
15 # The values to use for "blank" in SelectFields. Will be appended to the start of most "choices" lists.
16 BLANK_CHOICE_DASH = [("", "---------")]
17 BLANK_CHOICE_NONE = [("", "None")]
18
19 # Values for Relation.edit_inline.
20 TABULAR, STACKED = 1, 2
21
22 RECURSIVE_RELATIONSHIP_CONSTANT = 'self'
23
24 # prepares a value for use in a LIKE query
25 prep_for_like_query = lambda x: str(x).replace("%", "\%").replace("_", "\_")
26
27 # returns the <ul> class for a given radio_admin value
28 get_ul_class = lambda x: 'radiolist%s' % ((x == HORIZONTAL) and ' inline' or '')
29
30 def manipulator_valid_rel_key(f, self, field_data, all_data):
31     "Validates that the value is a valid foreign key"
32     mod = f.rel.to.get_model_module()
33     try:
34         mod.get_object(**{'id__iexact': field_data})
35     except ObjectDoesNotExist:
36         raise validators.ValidationError, "Please enter a valid %s." % f.verbose_name
37
38 def manipulator_validator_unique(f, opts, self, field_data, all_data):
39     "Validates that the value is unique for this field."
40     try:
41         old_obj = opts.get_model_module().get_object(**{'%s__exact' % f.name: field_data})
42     except ObjectDoesNotExist:
43         return
44     if hasattr(self, 'original_object') and getattr(self.original_object, opts.pk.name) == getattr(old_obj, opts.pk.name):
45         return
46     raise validators.ValidationError, "%s with this %s already exists." % (capfirst(opts.verbose_name), f.verbose_name)
47
48 class Field(object):
49
50     # Designates whether empty strings fundamentally are allowed at the
51     # database level.
52     empty_strings_allowed = True
53
54     def __init__(self, name, verbose_name=None, primary_key=False,
55         maxlength=None, unique=False, blank=False, null=False, db_index=None,
56         core=False, rel=None, default=NOT_PROVIDED, editable=True,
57         prepopulate_from=None, unique_for_date=None, unique_for_month=None,
58         unique_for_year=None, validator_list=None, choices=None, radio_admin=None,
59         help_text=''):
60         self.name = name
61         self.verbose_name = verbose_name or name.replace('_', ' ')
62         self.primary_key = primary_key
63         self.maxlength, self.unique = maxlength, unique
64         self.blank, self.null = blank, null
65         self.core, self.rel, self.default = core, rel, default
66         self.editable = editable
67         self.validator_list = validator_list or []
68         self.prepopulate_from = prepopulate_from
69         self.unique_for_date, self.unique_for_month = unique_for_date, unique_for_month
70         self.unique_for_year = unique_for_year
71         self.choices = choices or []
72         self.radio_admin = radio_admin
73         self.help_text = help_text
74         if rel and isinstance(rel, ManyToMany):
75             self.help_text += ' Hold down "Control", or "Command" on a Mac, to select more than one.'
76
77         # Set db_index to True if the field has a relationship and doesn't explicitly set db_index.
78         if db_index is None:
79             if isinstance(rel, OneToOne) or isinstance(rel, ManyToOne):
80                 self.db_index = True
81             else:
82                 self.db_index = False
83         else:
84             self.db_index = db_index
85
86     def pre_save(self, value, add):
87         "Returns field's value just before saving."
88         return value
89
90     def get_db_prep_save(self, value):
91         "Returns field's value prepared for saving into a database."
92        
93         # Oracle treats empty strings ('') the same as NULLs.
94         # To get around this wart, we need to change it to something else...
95         if value == '':
96             string_replacement = getattr(db,'EMPTY_STR_EQUIV','')
97             value = string_replacement
98         return value
99
100     def get_db_prep_lookup(self, lookup_type, value):
101         "Returns field's value prepared for database lookup."
102         if lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte', 'ne', 'month', 'day'):
103             return [value]
104         elif lookup_type in ('range', 'in'):
105             return value
106         elif lookup_type == 'year':
107             return ['%s-01-01' % value, '%s-12-31' % value]
108         elif lookup_type in ('contains', 'icontains'):
109             return ["%%%s%%" % prep_for_like_query(value)]
110         elif lookup_type == 'iexact':
111             return [prep_for_like_query(value)]
112         elif lookup_type in ('startswith', 'istartswith'):
113             return ["%s%%" % prep_for_like_query(value)]
114         elif lookup_type in ('endswith', 'iendswith'):
115             return ["%%%s" % prep_for_like_query(value)]
116         elif lookup_type == 'isnull':
117             return []
118         raise TypeError, "Field has invalid lookup: %s" % lookup_type
119
120     def has_default(self):
121         "Returns a boolean of whether this field has a default value."
122         return self.default != NOT_PROVIDED
123
124     def get_default(self):
125         "Returns the default value for this field."
126         if self.default != NOT_PROVIDED:
127             if hasattr(self.default, '__get_value__'):
128                 return self.default.__get_value__()
129             return self.default
130         if self.null:
131             return None
132         return ""
133
134     def get_manipulator_field_names(self, name_prefix):
135         """
136         Returns a list of field names that this object adds to the manipulator.
137         """
138         return [name_prefix + self.name]
139
140     def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False):
141         """
142         Returns a list of formfields.FormField instances for this field. It
143         calculates the choices at runtime, not at compile time.
144
145         name_prefix is a prefix to prepend to the "field_name" argument.
146         rel is a boolean specifying whether this field is in a related context.
147         """
148         params = {'validator_list': self.validator_list[:]}
149         if self.maxlength and not self.choices: # Don't give SelectFields a maxlength parameter.
150             params['maxlength'] = self.maxlength
151         if isinstance(self.rel, ManyToOne):
152             if self.rel.raw_id_admin:
153                 field_objs = self.get_manipulator_field_objs()
154                 params['validator_list'].append(curry(manipulator_valid_rel_key, self, manipulator))
155             else:
156                 if self.radio_admin:
157                     field_objs = [formfields.RadioSelectField]
158                     params['choices'] = self.get_choices(include_blank=self.blank, blank_choice=BLANK_CHOICE_NONE)
159                     params['ul_class'] = get_ul_class(self.radio_admin)
160                 else:
161                     if self.null:
162                         field_objs = [formfields.NullSelectField]
163                     else:
164                         field_objs = [formfields.SelectField]
165                     params['choices'] = self.get_choices()
166         elif self.choices:
167             if self.radio_admin:
168                 field_objs = [formfields.RadioSelectField]
169                 params['choices'] = self.get_choices(include_blank=self.blank, blank_choice=BLANK_CHOICE_NONE)
170                 params['ul_class'] = get_ul_class(self.radio_admin)
171             else:
172                 field_objs = [formfields.SelectField]
173                 params['choices'] = self.get_choices()
174         else:
175             field_objs = self.get_manipulator_field_objs()
176
177         # Add the "unique" validator(s).
178         for field_name_list in opts.unique_together:
179             if field_name_list[0] == self.name:
180                 params['validator_list'].append(getattr(manipulator, 'isUnique%s' % '_'.join(field_name_list)))
181
182         # Add the "unique for..." validator(s).
183         if self.unique_for_date:
184             params['validator_list'].append(getattr(manipulator, 'isUnique%sFor%s' % (self.name, self.unique_for_date)))
185         if self.unique_for_month:
186             params['validator_list'].append(getattr(manipulator, 'isUnique%sFor%s' % (self.name, self.unique_for_month)))
187         if self.unique_for_year:
188             params['validator_list'].append(getattr(manipulator, 'isUnique%sFor%s' % (self.name, self.unique_for_year)))
189         if self.unique or (self.primary_key and not rel):
190             params['validator_list'].append(curry(manipulator_validator_unique, self, opts, manipulator))
191
192         # Only add is_required=True if the field cannot be blank. Primary keys
193         # are a special case, and fields in a related context should set this
194         # as False, because they'll be caught by a separate validator --
195         # RequiredIfOtherFieldGiven.
196         params['is_required'] = not self.blank and not self.primary_key and not rel
197
198         # If this field is in a related context, check whether any other fields
199         # in the related object have core=True. If so, add a validator --
200         # RequiredIfOtherFieldsGiven -- to this FormField.
201         if rel and not self.blank and not isinstance(self, AutoField) and not isinstance(self, FileField):
202             # First, get the core fields, if any.
203             core_field_names = []
204             for f in opts.fields:
205                 if f.core and f != self:
206                     core_field_names.extend(f.get_manipulator_field_names(name_prefix))
207             # Now, if there are any, add the validator to this FormField.
208             if core_field_names:
209                 params['validator_list'].append(validators.RequiredIfOtherFieldsGiven(core_field_names, "This field is required."))
210
211         # BooleanFields (CheckboxFields) are a special case. They don't take
212         # is_required or validator_list.
213         if isinstance(self, BooleanField):
214             del params['validator_list'], params['is_required']
215
216         # Finally, add the field_names.
217         field_names = self.get_manipulator_field_names(name_prefix)
218         return [man(field_name=field_names[i], **params) for i, man in enumerate(field_objs)]
219
220     def get_manipulator_new_data(self, new_data, rel=False):
221         """
222         Given the full new_data dictionary (from the manipulator), returns this
223         field's data.
224         """
225         if rel:
226             return new_data.get(self.name, [self.get_default()])[0]
227         else:
228             val = new_data.get(self.name, self.get_default())
229             if not self.empty_strings_allowed and val == '' and self.null:
230                 val = None
231             return val
232
233     def get_choices(self, include_blank=True, blank_choice=BLANK_CHOICE_DASH):
234         "Returns a list of tuples used as SelectField choices for this field."
235         first_choice = include_blank and blank_choice or []
236         if self.choices:
237             return first_choice + list(self.choices)
238         rel_obj = self.rel.to
239         return first_choice + [(getattr(x, rel_obj.pk.name), repr(x)) for x in rel_obj.get_model_module().get_list(**self.rel.limit_choices_to)]
240
241 class AutoField(Field):
242     empty_strings_allowed = False
243     def __init__(self, *args, **kwargs):
244         assert kwargs.get('primary_key', False) is True, "%ss must have primary_key=True." % self.__class__.__name__
245         Field.__init__(self, *args, **kwargs)
246
247     def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False):
248         if not rel:
249             return [] # Don't add a FormField unless it's in a related context.
250         return Field.get_manipulator_fields(self, opts, manipulator, change, name_prefix, rel)
251
252     def get_manipulator_field_objs(self):
253         return [formfields.HiddenField]
254
255     def get_manipulator_new_data(self, new_data, rel=False):
256         if not rel:
257             return None
258         return Field.get_manipulator_new_data(self, new_data, rel)
259
260 class BooleanField(Field):
261     def __init__(self, *args, **kwargs):
262         kwargs['blank'] = True
263         Field.__init__(self, *args, **kwargs)
264
265     def get_db_prep_lookup(self, lookup_type, value):
266         if db.DATABASE_ENGINE == 'oracle':
267             if value == 'True':
268                 value = 1
269             elif value == 'False':
270                 value = 0
271         return Field.get_db_prep_lookup(self, lookup_type, value)
272
273     def get_manipulator_field_objs(self):
274         return [formfields.CheckboxField]
275
276 class CharField(Field):
277     def get_manipulator_field_objs(self):
278         return [formfields.TextField]
279
280 class CommaSeparatedIntegerField(CharField):
281     def get_manipulator_field_objs(self):
282         return [formfields.CommaSeparatedIntegerField]
283
284 class DateField(Field):
285     empty_strings_allowed = False
286     def __init__(self, name, verbose_name=None, auto_now=False, auto_now_add=False, **kwargs):
287         self.auto_now, self.auto_now_add = auto_now, auto_now_add
288         if auto_now or auto_now_add:
289             kwargs['editable'] = False
290         Field.__init__(self, name, verbose_name, **kwargs)
291
292     def get_db_prep_lookup(self, lookup_type, value):
293         if lookup_type == 'range':
294             value = [str(v) for v in value]
295         else:
296             value = str(value)
297         return Field.get_db_prep_lookup(self, lookup_type, value)
298
299     def pre_save(self, value, add):
300         if self.auto_now or (self.auto_now_add and add):
301             return datetime.datetime.now()
302         return value
303
304     def get_db_prep_save(self, value):
305         # Casts dates into string format for entry into database.
306         if value is not None:
307             if db.DATABASE_ENGINE != 'oracle':
308             #Oracle does not need a string conversion
309                 value = value.strftime('%Y-%m-%d')
310         return Field.get_db_prep_save(self, value)
311
312     def get_manipulator_field_objs(self):
313         return [formfields.DateField]
314
315 class DateTimeField(DateField):
316     def get_db_prep_save(self, value):
317         # Casts dates into string format for entry into database.
318         if value is not None:
319             if db.DATABASE_ENGINE != 'oracle':
320             #Oracle does not need a string conversion       
321                 value = value.strftime('%Y-%m-%d %H:%M:%S')
322         return Field.get_db_prep_save(self, value)
323
324     def get_manipulator_field_objs(self):
325         return [formfields.DateField, formfields.TimeField]
326
327     def get_manipulator_field_names(self, name_prefix):
328         return [name_prefix + self.name + '_date', name_prefix + self.name + '_time']
329
330     def get_manipulator_new_data(self, new_data, rel=False):
331         date_field, time_field = self.get_manipulator_field_names('')
332         if rel:
333             d = new_data.get(date_field, [None])[0]
334             t = new_data.get(time_field, [None])[0]
335         else:
336             d = new_data.get(date_field, None)
337             t = new_data.get(time_field, None)
338         if d is not None and t is not None:
339             return datetime.datetime.combine(d, t)
340         return self.get_default()
341
342 class EmailField(Field):
343     def get_manipulator_field_objs(self):
344         return [formfields.EmailField]
345
346 class FileField(Field):
347     def __init__(self, name, verbose_name=None, upload_to='', **kwargs):
348         self.upload_to = upload_to
349         Field.__init__(self, name, verbose_name, **kwargs)
350
351     def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False):
352         field_list = Field.get_manipulator_fields(self, opts, manipulator, change, name_prefix, rel)
353
354         if not self.blank:
355             if rel:
356                 # This validator makes sure FileFields work in a related context.
357                 class RequiredFileField:
358                     def __init__(self, other_field_names, other_file_field_name):
359                         self.other_field_names = other_field_names
360                         self.other_file_field_name = other_file_field_name
361                         self.always_test = True
362                     def __call__(self, field_data, all_data):
363                         if not all_data.get(self.other_file_field_name, False):
364                             c = validators.RequiredIfOtherFieldsGiven(self.other_field_names, "This field is required.")
365                             c(field_data, all_data)
366                 # First, get the core fields, if any.
367                 core_field_names = []
368                 for f in opts.fields:
369                     if f.core and f != self:
370                         core_field_names.extend(f.get_manipulator_field_names(name_prefix))
371                 # Now, if there are any, add the validator to this FormField.
372                 if core_field_names:
373                     field_list[0].validator_list.append(RequiredFileField(core_field_names, field_list[1].field_name))
374             else:
375                 v = validators.RequiredIfOtherFieldNotGiven(field_list[1].field_name, "This field is required.")
376                 v.always_test = True
377                 field_list[0].validator_list.append(v)
378                 field_list[0].is_required = field_list[1].is_required = False
379
380         # If the raw path is passed in, validate it's under the MEDIA_ROOT.
381         def isWithinMediaRoot(field_data, all_data):
382             f = os.path.abspath(os.path.join(settings.MEDIA_ROOT, field_data))
383             if not f.startswith(os.path.normpath(settings.MEDIA_ROOT)):
384                 raise validators.ValidationError, "Enter a valid filename."
385         field_list[1].validator_list.append(isWithinMediaRoot)
386         return field_list
387
388     def get_manipulator_field_objs(self):
389         return [formfields.FileUploadField, formfields.HiddenField]
390
391     def get_manipulator_field_names(self, name_prefix):
392         return [name_prefix + self.name + '_file', name_prefix + self.name]
393
394     def save_file(self, new_data, new_object, original_object, change, rel):
395         upload_field_name = self.get_manipulator_field_names('')[0]
396         if new_data.get(upload_field_name, False):
397             if rel:
398                 getattr(new_object, 'save_%s_file' % self.name)(new_data[upload_field_name][0]["filename"], new_data[upload_field_name][0]["content"])
399             else:
400                 getattr(new_object, 'save_%s_file' % self.name)(new_data[upload_field_name]["filename"], new_data[upload_field_name]["content"])
401
402     def get_directory_name(self):
403         return os.path.normpath(datetime.datetime.now().strftime(self.upload_to))
404
405     def get_filename(self, filename):
406         from django.utils.text import get_valid_filename
407         f = os.path.join(self.get_directory_name(), get_valid_filename(os.path.basename(filename)))
408         return os.path.normpath(f)
409
410 class FloatField(Field):
411     empty_strings_allowed = False
412     def __init__(self, name, verbose_name=None, max_digits=None, decimal_places=None, **kwargs):
413         self.max_digits, self.decimal_places = max_digits, decimal_places
414         Field.__init__(self, name, verbose_name, **kwargs)
415
416     def get_manipulator_field_objs(self):
417         return [curry(formfields.FloatField, max_digits=self.max_digits, decimal_places=self.decimal_places)]
418
419 class ImageField(FileField):
420     def __init__(self, name, verbose_name=None, width_field=None, height_field=None, **kwargs):
421         self.width_field, self.height_field = width_field, height_field
422         FileField.__init__(self, name, verbose_name, **kwargs)
423
424     def get_manipulator_field_objs(self):
425         return [formfields.ImageUploadField, formfields.HiddenField]
426
427     def save_file(self, new_data, new_object, original_object, change, rel):
428         FileField.save_file(self, new_data, new_object, original_object, change, rel)
429         # If the image has height and/or width field(s) and they haven't
430         # changed, set the width and/or height field(s) back to their original
431         # values.
432         if change and (self.width_field or self.height_field):
433             if self.width_field:
434                 setattr(new_object, self.width_field, getattr(original_object, self.width_field))
435             if self.height_field:
436                 setattr(new_object, self.height_field, getattr(original_object, self.height_field))
437             new_object.save()
438
439 class IntegerField(Field):
440     empty_strings_allowed = False
441     def get_manipulator_field_objs(self):
442         return [formfields.IntegerField]
443
444 class IPAddressField(Field):
445     def __init__(self, *args, **kwargs):
446         kwargs['maxlength'] = 15
447         Field.__init__(self, *args, **kwargs)
448
449     def get_manipulator_field_objs(self):
450         return [formfields.IPAddressField]
451
452 class NullBooleanField(Field):
453     def __init__(self, *args, **kwargs):
454         kwargs['null'] = True
455         Field.__init__(self, *args, **kwargs)
456
457     def get_manipulator_field_objs(self):
458         return [formfields.NullBooleanField]
459
460 class PhoneNumberField(IntegerField):
461     def get_manipulator_field_objs(self):
462         return [formfields.PhoneNumberField]
463
464 class PositiveIntegerField(IntegerField):
465     def get_manipulator_field_objs(self):
466         return [formfields.PositiveIntegerField]
467
468 class PositiveSmallIntegerField(IntegerField):
469     def get_manipulator_field_objs(self):
470         return [formfields.PositiveSmallIntegerField]
471
472 class SlugField(Field):
473     def __init__(self, *args, **kwargs):
474         kwargs['maxlength'] = 50
475         kwargs.setdefault('validator_list', []).append(validators.isAlphaNumeric)
476         # Set db_index=True unless it's been set manually.
477         if not kwargs.has_key('db_index'):
478             kwargs['db_index'] = True
479         Field.__init__(self, *args, **kwargs)
480
481     def get_manipulator_field_objs(self):
482         return [formfields.TextField]
483
484 class SmallIntegerField(IntegerField):
485     def get_manipulator_field_objs(self):
486         return [formfields.SmallIntegerField]
487
488 class TextField(Field):
489     def get_manipulator_field_objs(self):
490         return [formfields.LargeTextField]
491
492 class TimeField(Field):
493     empty_strings_allowed = False
494     def __init__(self, name, verbose_name=None, auto_now=False, auto_now_add=False, **kwargs):
495         self.auto_now, self.auto_now_add  = auto_now, auto_now_add
496         if auto_now or auto_now_add:
497             kwargs['editable'] = False
498         Field.__init__(self, name, verbose_name, **kwargs)
499
500     def get_db_prep_lookup(self, lookup_type, value):
501         if lookup_type == 'range':
502             value = [str(v) for v in value]
503         else:
504             value = str(value)
505         return Field.get_db_prep_lookup(self, lookup_type, value)
506
507     def pre_save(self, value, add):
508         if self.auto_now or (self.auto_now_add and add):
509             return datetime.datetime.now().time()
510         return value
511
512     def get_db_prep_save(self, value):
513         # Casts dates into string format for entry into database.
514         if value is not None:
515             if db.DATABASE_ENGINE != 'oracle':
516             #Oracle does not need a string conversion           
517                 value = value.strftime('%H:%M:%S')
518         return Field.get_db_prep_save(self, value)
519
520     def get_manipulator_field_objs(self):
521         return [formfields.TimeField]
522
523 class URLField(Field):
524     def __init__(self, name, verbose_name=None, verify_exists=True, **kwargs):
525         if verify_exists:
526             kwargs.setdefault('validator_list', []).append(validators.isExistingURL)
527         Field.__init__(self, name, verbose_name, **kwargs)
528
529     def get_manipulator_field_objs(self):
530         return [formfields.URLField]
531
532 class USStateField(Field):
533     def get_manipulator_field_objs(self):
534         return [formfields.USStateField]
535
536 class XMLField(Field):
537     def __init__(self, name, verbose_name=None, schema_path=None, **kwargs):
538         self.schema_path = schema_path
539         Field.__init__(self, name, verbose_name, **kwargs)
540
541     def get_manipulator_field_objs(self):
542         return [curry(formfields.XMLLargeTextField, schema_path=self.schema_path)]
543
544 class ForeignKey(Field):
545     empty_strings_allowed = False
546     def __init__(self, to, to_field=None, rel_name=None, **kwargs):
547         try:
548             to_name = to._meta.object_name.lower()
549         except AttributeError: # to._meta doesn't exist, so it must be RECURSIVE_RELATIONSHIP_CONSTANT
550             assert to == 'self', "ForeignKey(%r) is invalid. First parameter to ForeignKey must be either a model or the string %r" % (to, RECURSIVE_RELATIONSHIP_CONSTANT)
551             kwargs['name'] = kwargs.get('name', '')
552             kwargs['verbose_name'] = kwargs.get('verbose_name', '')
553         else:
554             to_field = to_field or to._meta.pk.name
555             kwargs['name'] = kwargs.get('name', to_name + '_id')
556             kwargs['verbose_name'] = kwargs.get('verbose_name', to._meta.verbose_name)
557             rel_name = rel_name or to_name
558
559         if kwargs.has_key('edit_inline_type'):
560             import warnings
561             warnings.warn("edit_inline_type is deprecated. Use edit_inline instead.")
562             kwargs['edit_inline'] = kwargs.pop('edit_inline_type')
563
564         kwargs['rel'] = ManyToOne(to, rel_name, to_field,
565             num_in_admin=kwargs.pop('num_in_admin', 3),
566             min_num_in_admin=kwargs.pop('min_num_in_admin', None),
567             max_num_in_admin=kwargs.pop('max_num_in_admin', None),
568             num_extra_on_change=kwargs.pop('num_extra_on_change', 1),
569             edit_inline=kwargs.pop('edit_inline', False),
570             related_name=kwargs.pop('related_name', None),
571             limit_choices_to=kwargs.pop('limit_choices_to', None),
572             lookup_overrides=kwargs.pop('lookup_overrides', None),
573             raw_id_admin=kwargs.pop('raw_id_admin', False))
574         Field.__init__(self, **kwargs)
575
576     def get_manipulator_field_objs(self):
577         return [formfields.IntegerField]
578
579 class ManyToManyField(Field):
580     def __init__(self, to, rel_name=None, **kwargs):
581         kwargs['name'] = kwargs.get('name', to._meta.module_name)
582         kwargs['verbose_name'] = kwargs.get('verbose_name', to._meta.verbose_name_plural)
583         rel_name = rel_name or to._meta.object_name.lower()
584         kwargs['rel'] = ManyToMany(to, rel_name,
585             num_in_admin=kwargs.pop('num_in_admin', 0),
586             related_name=kwargs.pop('related_name', None),
587             filter_interface=kwargs.pop('filter_interface', None),
588             limit_choices_to=kwargs.pop('limit_choices_to', None))
589         Field.__init__(self, **kwargs)
590
591     def get_manipulator_field_objs(self):
592         choices = self.get_choices(include_blank=False)
593         return [curry(formfields.SelectMultipleField, size=min(max(len(choices), 5), 15), choices=choices)]
594
595     def get_m2m_db_table(self, original_opts):
596         "Returns the name of the many-to-many 'join' table."
597         return '%s_%s' % (original_opts.db_table, self.name)
598
599 class OneToOneField(IntegerField):
600     def __init__(self, to, to_field=None, rel_name=None, **kwargs):
601         kwargs['name'] = kwargs.get('name', 'id')
602         kwargs['verbose_name'] = kwargs.get('verbose_name', 'ID')
603         to_field = to_field or to._meta.pk.name
604         rel_name = rel_name or to._meta.object_name.lower()
605
606         if kwargs.has_key('edit_inline_type'):
607             import warnings
608             warnings.warn("edit_inline_type is deprecated. Use edit_inline instead.")
609             kwargs['edit_inline'] = kwargs.pop('edit_inline_type')
610
611         kwargs['rel'] = OneToOne(to, rel_name, to_field,
612             num_in_admin=kwargs.pop('num_in_admin', 0),
613             edit_inline=kwargs.pop('edit_inline', False),
614             related_name=kwargs.pop('related_name', None),
615             limit_choices_to=kwargs.pop('limit_choices_to', None),
616             lookup_overrides=kwargs.pop('lookup_overrides', None),
617             raw_id_admin=kwargs.pop('raw_id_admin', False))
618         kwargs['primary_key'] = True
619         IntegerField.__init__(self, **kwargs)
620
621 class ManyToOne:
622     def __init__(self, to, name, field_name, num_in_admin=3, min_num_in_admin=None,
623         max_num_in_admin=None, num_extra_on_change=1, edit_inline=False,
624         related_name=None, limit_choices_to=None, lookup_overrides=None, raw_id_admin=False):
625         try:
626             self.to = to._meta
627         except AttributeError: # to._meta doesn't exist, so it must be RECURSIVE_RELATIONSHIP_CONSTANT
628             assert to == RECURSIVE_RELATIONSHIP_CONSTANT, "'to' must be either a model or the string '%s'" % RECURSIVE_RELATIONSHIP_CONSTANT
629             self.to = to
630         self.name, self.field_name = name, field_name
631         self.num_in_admin, self.edit_inline = num_in_admin, edit_inline
632         self.min_num_in_admin, self.max_num_in_admin = min_num_in_admin, max_num_in_admin
633         self.num_extra_on_change, self.related_name = num_extra_on_change, related_name
634         self.limit_choices_to = limit_choices_to or {}
635         self.lookup_overrides = lookup_overrides or {}
636         self.raw_id_admin = raw_id_admin
637
638     def get_cache_name(self):
639         return '_%s_cache' % self.name
640
641     def get_related_field(self):
642         "Returns the Field in the 'to' object to which this relationship is tied."
643         return self.to.get_field(self.field_name)
644
645 class ManyToMany:
646     def __init__(self, to, name, num_in_admin=0, related_name=None,
647         filter_interface=None, limit_choices_to=None):
648         self.to, self.name = to._meta, name
649         self.num_in_admin = num_in_admin
650         self.related_name = related_name
651         self.filter_interface = filter_interface
652         self.limit_choices_to = limit_choices_to or {}
653         self.edit_inline = False
654
655 class OneToOne(ManyToOne):
656     def __init__(self, to, name, field_name, num_in_admin=0, edit_inline=False,
657         related_name=None, limit_choices_to=None, lookup_overrides=None,
658         raw_id_admin=False):
659         self.to, self.name, self.field_name = to._meta, name, field_name
660         self.num_in_admin, self.edit_inline = num_in_admin, edit_inline
661         self.related_name = related_name
662         self.limit_choices_to = limit_choices_to or {}
663         self.lookup_overrides = lookup_overrides or {}
664         self.raw_id_admin = raw_id_admin
665
666 class Admin:
667     def __init__(self, fields=None, js=None, list_display=None, list_filter=None, date_hierarchy=None,
668         save_as=False, ordering=None, search_fields=None, save_on_top=False):
669         self.fields = fields
670         self.js = js or []
671         self.list_display = list_display or ['__repr__']
672         self.list_filter = list_filter or []
673         self.date_hierarchy = date_hierarchy
674         self.save_as, self.ordering = save_as, ordering
675         self.search_fields = search_fields or []
676         self.save_on_top = save_on_top
677
678     def get_field_objs(self, opts):
679         """
680         Returns self.fields, except with fields as Field objects instead of
681         field names. If self.fields is None, defaults to putting every
682         non-AutoField field with editable=True in a single fieldset.
683         """
684         if self.fields is None:
685             field_struct = ((None, {'fields': [f.name for f in opts.fields + opts.many_to_many if f.editable and not isinstance(f, AutoField)]}),)
686         else:
687             field_struct = self.fields
688         new_fieldset_list = []
689         for fieldset in field_struct:
690             new_fieldset = [fieldset[0], {}]
691             new_fieldset[1].update(fieldset[1])
692             admin_fields = []
693             for field_name_or_list in fieldset[1]['fields']:
694                 if isinstance(field_name_or_list, basestring):
695                     admin_fields.append([opts.get_field(field_name_or_list)])
696                 else:
697                     admin_fields.append([opts.get_field(field_name) for field_name in field_name_or_list])
698             new_fieldset[1]['fields'] = admin_fields
699             new_fieldset_list.append(new_fieldset)
700         return new_fieldset_list