class BillingInfo(models.Model):
customer = models.OneToOneField(Customer)
billing_address = models.OneToOneField(Address)
and then just have logic in the views and templates to account for
existence/nonexistence of a given customer's billing address.
On Dec 28, 9:21 am, Dan Gentry <dgen...@gmail.com> wrote:
> Just looking at the models, I'd like to make a couple of suggestions.
>
> Instead of using a Foreign Key relationship in Customer to indicate
> the billing address, I would include a flag called 'billing_address'
> in the Address table that would be set to True for the customer
> selected address.
>
> An override of save() in the Address model is then used to enforce the
> 'only one billing address' rule.
>
> def save(self):
> ''' This will turn off the billing address flag for all other
> addresses for this customer if the new record is selected '''
> if self.billing_address:
> old_billing_address =
> Address.objects.filter(customer=self.customer).filter(billing_flag=
> True)
> for s in old_billing_address:
> s.billing_flag = False
> s.save()
> super(Address, self).save()
>
> Hope this helps,
>
> Dan
>
> On Dec 28, 6:02 am, Bart Nagel <b...@tremby.net> wrote:
>
>
>
>
>
>
>
> > I'm new to Django. I'm finding it very impressive so far but have hit
> > a cluster of problems. I'm using the SVN version.
>
> > Sorry for the length of this, I'm just trying to explain as fully as I
> > can what I'm trying to do, what I have and what's going wrong.
>
> > The relevant parts of my model, in the simplest terms, look like this.
>
> > from django.db import models
>
> > class Address(models.Model):
> > customer = models.ForeignKey("Customer")
> > street = models.CharField(max_length=128)
> > city = models.CharField(max_length=128)
>
> > def __unicode__(self):
> > return "%s, %s" % (self.street, self.city)
>
> > class Customer(models.Model):
> > last_name = models.CharField(blank=True, max_length=64)
> > first_name = models.CharField(blank=True, max_length=64)
> > billing_address = models.ForeignKey("Address", related_name="+")
>
> > def __unicode__(self):
> > return "%s %s" % (self.first_name, self.last_name)
>
> > So customers can have many addresses, and one of those addresses is
> > pointed to by the customer as being the billing address.
>
> > I then have the Customer admin page set up so that Address entries are
> > edited inline on the same form.
>
> > 1. The billing address should be required, but obviously when it's a
> > new Customer there won't be any addresses on file, so there will be
> > no choices on the billing address dropdown.
>
> > So I need a way to accept a blank selection for billing address,
> > maybe have it labelled as "use first address given below", and then
> > just complain if no addresses are given below.
>
> > Later when there needs to be something to stop the billing address
> > from being deleted.
>
> > 2. Related to the previous, there needs to be a constraint so there
> > must be at least one Address for each customer.
>
> > 3. When editing an existing customer, only that customer's addresses
> > should be shown in the dropdown for billing address.
>
> > Here's what I've tried...
>
> > I set the billing address field to be optional for now.
>
> > Problem 3 seemed easiest so I decided to tackle that first, and made a
> > bunch of customers and addresses so I could test with the database
> > somewhat populated.
>
> > I found the ForeignKey.limit_choices_to in the documentation but since
> > there's no "self" when I'm setting up the database fields I've no idea
> > how I'd tell it to limit the options to something like
> > self.addresses_set.all(), let alone have that updated as addresses are
> > added, removed, edited in the inline form below.
>
> > I first posted this problem on Stacko Overflow
> > (http://stackoverflow.com/questions/8637912/) and a suggestion was to
> > use a ModelChoiceField. I had a look at the documentation and it
> > wasn't obvious what the difference is between that an ForeignKey, plus
> > it looks like I'd have exactly the same problem as above.
>
> > So I'm totally stuck on that one.
>
> > Next I had a go at the other two problems. It seemed to me (bearing in
> > mind I'm a newbie here) it'd be best to add that logic to the
> > Customer.clean() method -- I could check the number of addresses which
> > had been entered there and raise an Exception if it was zero. At the
> > same time I could set the billing address, if not already set, to the
> > first address given. All sounds simple enough, but apparently not.
>
> > In the Customer.clean() method, I can't seem to get at what was posted
> > as addresses. In there, self.address_set.all().count() is zero. I
> > don't really see why -- I can get at the other data which was posted
> > to the form as an object, why not the child objects which are being
> > posted too?
>
> > Perhaps just too early. Following a suggestion in the same Stack
> > Overflow thread mentioned above, I figured out how to set up a
> > listeners for the pre_save and post_save signals and inspected the
> > count of addresses at those points. It's still zero in both cases.
> > Even after the save. That was very confusing but from what I've found
> > while Googling it's something to do with the database transaction
> > having not been finished yet. It seems counter-intuitive. Ideally I'd
> > like to get at the Address objects before they're committed to the
> > database so that I can roll back if necessary (in the case that there
> > are no addresses), but after they're committed would do if there was
> > no other way -- I could change the Customer object as necessary and
> > re-save it or delete it. Not sure how I'd let the user know in that
> > case.
>
> > But no -- empty address_set.all() at post_save time. I found a monkey
> > patch to add a signal for post_transaction
> > (https://gist.github.com/247844) and with a small tweak (possibly my
> > Python or my Django is too old or new or something) it worked. I set
> > up the listener and now I can get at the Address objects from the
> > Customer object and edit the Customer if necessary (adding the first
> > address as the billing address). But at this point it's too late to
> > throw pretty exceptions if something goes wrong, which is a shame.
>
> > There's another problem there too. Once the billing address is set to
> > one of the addresses and then the customer's addresses are later
> > edited again I get horrific errors saying that the billing address is
> > set to an unacceptable option. I think what's happening is that the
> > addresses are being deleted and recreated, and so the reference in the
> > billing address field now points to a non-existent primary key in the
> > addresses table.
>
> > Since the above doesn't let me warn the user if they haven't entered
> > any addresses, I needed another approach to let me do that. What I
> > came up with was setting up a custom ModelForm for the Customer
> > object's admin interface, and checking in the clean() method there.
> > The best I could think to do was to print out dir() of various things
> > to find likely looking methods and to see what data I had. The only
> > reference to the addresses being entered I could find was in the
> > self.data dict there. And it's messy, but I got a solution
> > half-working by looking at self.data["address_set-TOTAL_FORMS"] and
> > checking the number. But that doesn't cover all possibilities -- it
> > might not exist (easy to deal with) and, slightly harder, some of the
> > forms sent might have the "delete" box checked. So I had to count up
> > to the number of forms and look for "address_set-%n-DELETE" keys. It's
> > a mess and there's still a case it doesn't catch -- when a form is
> > sent with the default (untouched) values and so doesn't actually end
> > up creating an address. I'd see it as being an address and let it
> > through, but then the billing address wouldn't have anything to point
> > to. I didn't try to write code to handle that case because it's just
> > getting way too messy.
>
> > So this solution is not working for me.
>
> > In fact, looking back, none of my solutions for any of the problems
> > are adequate. I'm stuck.
>
> > Please help! Any suggestions are appreciated. Hopefully there are just
> > some really easy things I've missed in the documents which will solve
> > everything, but if the solution is a bit more in depth, so be it.
>
> > --bart nagel
--
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+unsubscribe@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/django-users?hl=en.
No comments:
Post a Comment