Django model inheritance
I am trying to fix rsvp system on my site. I have Contact model which is linked to User model. Guest model is linked to Contact and Event models.
class Contact(models.Model):
first_name = models.CharField(_("First name"), max_length=30, )
last_name = models.CharField(_("Last name"), max_length=30, )
user = models.ForeignKey(User, unique=True)
dob = models.DateField(_("Date of birth"), blank=True, null=True)
email = models.EmailField(_("Email"), blank=True, max_length=75)
notes = models.TextField(_("Notes"), max_length=500, blank=True)
create_date = models.DateField(_("Creation date"))
class Guest(models.Model):
event = models.ForeignKey(Event, related_name='guests')
contact = models.ForeignKey(Contact, related_name='guests')
attending_status = models.CharField(max_length=32, choices=ATTENDING_CHOICES, default='no_rsvp')
number_of_guests = models.SmallIntegerField(default=0)
comment = models.CharField(max_len开发者_如何学Cgth=255, blank=True, default='')
updated = models.DateTimeField(blank=True, null=True)
def _get_email(self):
return u'%s' % (self.contact.email)
email = property(_get_email)
....
I try to fix RSVP form on the base of the Guest model:
class RSVPForm(forms.Form):
email = forms.EmailField()
name = forms.CharField(max_length=128)
attending = forms.ChoiceField(choices=VISIBLE_ATTENDING_CHOICES, initial='yes', widget=forms.RadioSelect)
number_of_guests = forms.IntegerField(initial=0)
comment = forms.CharField(max_length=255, required=False, widget=forms.Textarea)
def __init__(self, *args, **kwargs):
if 'guest_class' in kwargs:
self.guest_class = kwargs['guest_class']
del(kwargs['guest_class'])
else:
self.guest_class = Guest
super(RSVPForm, self).__init__(*args, **kwargs)
def clean_email(self):
try:
guest = self.guest_class.objects.get(email=self.cleaned_data['email'])
except ObjectDoesNotExist:
raise forms.ValidationError, 'That e-mail is not on the guest list.'
if hasattr(guest, 'attending_status') and guest.attending_status != 'no_rsvp':
raise forms.ValidationError, 'You have already provided RSVP information.'
return self.cleaned_data['email']
def clean_number_of_guests(self):
if self.cleaned_data['number_of_guests'] < 0:
raise forms.ValidationError, "The number of guests you're bringing can not be negative."
return self.cleaned_data['number_of_guests']
def save(self):
guest = self.guest_class.objects.get(email=self.cleaned_data['email'])
if self.cleaned_data['name']:
guest.name = self.cleaned_data['name']
guest.attending_status = self.cleaned_data['attending']
guest.number_of_guests = self.cleaned_data['number_of_guests']
guest.comment = self.cleaned_data['comment']
guest.save()
return guest
This form is processed by the following view:
@login_required
def event_view(request, slug, model_class=Event, form_class=RSVPForm, template_name='rsvp/event_view.html'):
event = get_object_or_404(model_class, slug=slug)
if request.POST:
form = form_class(request.POST)
if form.is_valid():
guest = form.save()
return HttpResponseRedirect(reverse('rsvp_event_thanks', kwargs={'slug': slug, 'guest_id': guest.id}))
else:
form = form_class()
return render_to_response(template_name, {
'event': event,
'form': form,
}, context_instance=RequestContext(request))
After submitting the form, I get the following error:
"Cannot resolve keyword 'email' into field. Choices are: attending_status, comment, contact, event, id, number_of_guests, updated"
After hours of searching the web, i still can't figure out why I have just "contact" in the choice list while i'm working with Guest.email which renders its value from Contact.email..
A Guest in your models does not have the field email. It is on your Contact model.
You didn't mention which line triggered your error, but I'm guessing it would be one of these:
guest = self.guest_class.objects.get(email=self.cleaned_data['email'])
If you are searching for a guest that is linked to a contact with the given email, you will want to change it to use contact__email
so it will do the join for you:
guest = self.guest_class.objects.get(contact__email=self.cleaned_data['email'])
A source of your problem is perhaps thinking that you have an inheritance relationship between your models where I don't see one at all. You have a simple ForeignKey relationship, which should work for you, just don't confuse it with inheritance, where you would set up a Guest to inherit the properties of Contact through subclassing.
Because django's ORM works on the SQL level. There is no 'email' column (or defined field) in your tables / model, only a python property. Django doesn't know it needs to do a JOIN to your other table.
Instead, just use django's __
JOIN / field lookup syntax:
guest = self.guest_class.objects.get(contact__email=self.cleaned_data['email'])
http://docs.djangoproject.com/en/dev/topics/db/queries/#lookups-that-span-relationships
精彩评论