2

I'm following Beginning Django E-Commerce but I found a part regarding user profiles a bit perplexing. Basically, I have an abstract class like this:

class BaseOrderInfo(models.Model):
  class Meta:
    abstract = True
    # a bunch of fields follow
    shipping_name = models.CharField()
    # etc

After this, a UserProfile class inherits BaseOrderInfo:

class UserProfile(BaseOrderInfo):
  user = models.ForeignKey(User, unique = True)
  # Possibly other methods or fields here

Finally, there is a retrieve method which, as its name suggests, retrieves a user profile (if this user profile doesn't exist, it creates one for that User object):

def retrieve(request):
  try:
    profile = request.user.get_profile()
  except UserProfile.DoesNotExist:
    profile = UserProfile(user=request.user)
    profile.save()
  return profile

Well, my question is the following: How is it possible to save this UserProfile instance in the retrieve method by only adding a User instance given the fact that UserProfile inherited quite a few other fields from the BaseOrderInfo class? As far as I know, Model and ModelForm create required fields by default.

Thanks

r_31415
  • 8,752
  • 17
  • 74
  • 121

2 Answers2

1

If the UserProfile has any required fields, you need to present a form to the user to collect that data first. You could integrate it into your registration form or simply present a separate profile form whenever you need to access user profile data but determine the profile doesn't exist yet.

Chris Pratt
  • 232,153
  • 36
  • 385
  • 444
  • Thanks for your answer. In this case, I wrote the classes as in the book. UserProfile doesn't have any more fields, however, BaseOrderInfo has quite a few of them. As fields in subclasses of models.Model are required by default and BaseOrderInfo doesn't include any field using "required=False", it seems to me that profile.save() shouldn't work. – r_31415 Nov 01 '11 at 19:24
  • Seems you don't understand inheritance. `BaseOrderInfo` is an abstract class; it doesn't exist on its own, but rather, merely provides a template. When you make `UserProfile` inherit from it, `UserProfile` has all those fields as if you had simply put them on the `UserProfile` class itself. The same instructions apply. If there's required fields, you must provide a form for the user to enter that data. – Chris Pratt Nov 01 '11 at 19:29
  • Maybe I didn't express myself correctly. I understand the inheritance part, but I want to know why UserProfile fields inherited from BaseOrderInfo are 'ignored' when saving the instance of UserProfile, assuming that those fields are required by default. I think @Alasdair points out to the solution: save() doesn't validate. – r_31415 Nov 01 '11 at 19:33
  • Sorry, yes indeed, @Alasdair is correct about validation. You just happened to have a set of fields that could all receive empty strings as defaults. Other types of fields such as a foreign key or a datetime would have stopped you dead. – Chris Pratt Nov 01 '11 at 19:37
  • datefield fields are required because of the point 3 in https://docs.djangoproject.com/en/dev/ref/models/instances/#what-happens-when-you-save? – r_31415 Nov 01 '11 at 19:42
  • 1
    re: datetimes fields - not quite. Try it. I think Django will attempt to insert null, so you'll get an `IntegrityError`. The difference for a `CharField` is that Django inserts the empty string, not `null`. – Alasdair Nov 01 '11 at 20:18
1

Django does not validate the model when the form is saved. (See the docs on Validating Objects). If you explicitly call profile.full_clean() before saving, then you will see the validation errors.

If a required foreign key was not specified, then you would get a database IntegrityError. Other required fields are validated by Django, not the database. If Django does not validate the model, there will not be any errors saving an empty string to a CharField in the database.

Alasdair
  • 298,606
  • 55
  • 578
  • 516
  • Oh, now I see. save() doesn't call full_clean(). However, https://docs.djangoproject.com/en/dev/ref/models/instances/#what-happens-when-you-save describes the process of saving and point 4 and 5 look like they should validate before inserting SQL statements into the database. Could you clarify that part? – r_31415 Nov 01 '11 at 19:36
  • pre-processing and preparing is not the same as validating, although they may raise validation errors e.g. empty `datetime` as @Chris suggested. When a `CharField` in the `UserProfile` instance is asked to prepare it's value for the database, it returns the default, `u""`. It's not being asked to validate the value. – Alasdair Nov 01 '11 at 20:09
  • 1
    If the docs don't give enough info, then you can have a look at the `pre_save` and `get_prep_value` methods for the different fields in the source code: https://code.djangoproject.com/browser/django/trunk/django/db/models/fields/__init__.py – Alasdair Nov 01 '11 at 20:19
  • Thanks. By the way, is it there a way to search easily for a function in the Django source code? – r_31415 Nov 01 '11 at 21:05
  • I search the source code by grepping my local svn checkout. I'm not aware of any way to search the source code online. – Alasdair Nov 01 '11 at 21:41