Hi Django users,

I want a ManyToManyField(A) to be shown in a textarea as a formatted
list of a model field _x_ in the corresponding related model A (not a
list of the A's pk field, which is easier). If a value for _x_ that
does not exist in A is added, then I want a new record added to A (by
implication, field _x_ is unique).

I have recently implemented this as follows, and it works but I (I
think) but I want to know if I went about it the right way. Any
comments would be appreciated. (Also, it's a useful bit of code, so
you should check it out.)

As an example, consider the following models for University courses:

class Student(models.Model):
    email = models.EmailField(unique=True)
    ...

class Course(models.Model):
    name = models.CharField(max_length = 100)
    students = models.ManyToManyField(Student)
    ...

I want the administrator to be able to enter a comma separated list of
emails into a textarea. If the email does not exist in Student, a new
Student should be added.

To solve this, I have

class CourseAdmin(admin.ModelAdmin):
    form = CourseForm
    ...

class CourseForm(ModelForm):
    students = MultiEmailField()
    def __init__(self, *args, **kwargs):
        super(CourseForm, self).__init__(*args, **kwargs)
        if self.initial.has_key('students'):
            self.initial['students'] = ",".join(
                [course_student.email for course_student in
CourseStudent.objects.filter(pk__in = self.initial['students'])])

    def save(self, *args, **kwargs):
        emails = self.cleaned_data['students']
        for email in emails:
            # create a new Student if one does not already exist
            form = StudentForm({'email': email})
            if form.is_valid():
                form.save()
        self.cleaned_data['students'] = Student.objects.filter
(email__in=emails)
        return super(CourseForm, self).save(*args, **kwargs)

    class Meta:
        model = Course

class StudentForm(ModelForm):
    class Meta:
        model = Student

MultiEmailField is essentially the same as specified in
http://docs.djangoproject.com/en/dev/ref/forms/validation/#form-field-default-cleaning.
Assume is_valid_email is defined, and don't worry about the details of
MultiEmailField (the actual implementation lets you use spaces,
semicolons, commas and newlines as delimiters):

class MultiEmailField(forms.Field):
    def clean(self, value):
        """
        Check that the field contains one or more comma-separated
emails
        and normalizes the data to a list of the email strings.
        """
        if not value:
            raise forms.ValidationError('Enter at least one e-mail
address.')
        emails = value.split(',')
        for email in emails:
            if not is_valid_email(email):
                raise forms.ValidationError('%s is not a valid e-mail
address.' % email)

        # Always return the cleaned data.
        return emails

Please comment on my code in CourseForm:

* Does the logic belong here instead of in the model?
* Are there bugs that you can see?
* Is this the right way to do things?
* Is it elegant? (I think the answer is no.)

Any comments are appreciated.

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To post to this group, send email to django-users@googlegroups.com
To unsubscribe from this group, send email to 
django-users+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/django-users?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to