English 中文(简体)
django-ajax-selects app: How do I create a new object when there isn t already one in the database?
原标题:

I m using django-ajax-selects, which is a freely available django app providing jquery autocomplete functionality.

I ve got it working - i.e. it is autocompleting the form fields I want it to. But I have a problem... I m using it in a ModelForm which adds Partnership objects to the database:

class Skater(models.Model):
    name = models.CharField(max_length=64)
    surname = models.CharField(max_length=64)
    gender = models.CharField(max_length=1, choices=GENDER_CHOICES)

class Partnership(models.Model):
    female_partner = models.ForeignKey(Skater, limit_choices_to = { gender : FEMALE}, related_name= female_partner_set )
    male_partner = models.ForeignKey(Skater, limit_choices_to = { gender : MALE}, related_name= male_partner_set )

I want the user to be able to put in a name and surname into the female_partner and male_partner field even if a Skater object like that doesn t exist and I want that object created. How do I go about doing this? I cannot put the code in the form s save method because the field won t validate (it s not a valid Skater).

EDIT 1: Adding in more code...

The form:

class PartnershipAddForm(forms.ModelForm):
    female_partner = AutoCompleteSelectField( female_skater ,required=True)
    male_partner = AutoCompleteSelectField( male_skater ,required=True)

    class Meta:
        model = Partnership

settings.py:

AJAX_LOOKUP_CHANNELS = {
     female_skater  : ( skaters.lookups ,  FemaleLookup ),
     male_skater  : ( skaters.lookups ,  MaleLookup ),
}

lookups.py (MaleLookup is the same except that gender=MALE):

class FemaleLookup(object):

    def get_query(self,q,request):
        """ return a query set.  you also have access to request.user if needed """
        return Skater.objects.filter(Q(gender=FEMALE) & (Q(name__istartswith=q) | Q(surname__istartswith=q)))

    def format_item(self,skater):
        """ simple display of an object when it is displayed in the list of selected objects """
        return unicode(skater)

    def format_result(self,skater):
        """ a more verbose display, used in the search results display.  may contain html and multi-lines """
        return "%s<br/>" % unicode(skater)

    def get_objects(self,ids):
        """ given a list of ids, return the objects ordered as you would like them on the admin page.
            this is for displaying the currently selected items (in the case of a ManyToMany field)
        """
        return Skater.objects.filter(pk__in=ids).order_by( name , surname )
最佳回答

AutoCompleteSelectField holds the id of the object rather than the text, which is why I had the "required" error all along (and why Daniel s solution doesn t work). The value variable was empty as a Skater that doesn t exist doesn t have an id.

I m not sure this is the best way of doing this, but I ended up using AutoCompleteField instead of AutoCompleteSelectField. AutoCompleteField holds text, but it doesn t create a Skater object for me.

The code:

class PartnershipAddForm(forms.ModelForm):
    female_partner = AutoCompleteField( female_skater ,required=True)
    male_partner = AutoCompleteField( male_skater ,required=True)

    class Meta:
        model = Partnership

    def save(self):
        partners = [self.cleaned_data[ female_partner ],
                    self.cleaned_data[ male_partner ]]
        name = [  ,  ]
        surname = [  ,  ]
        for i in [0,1]:
            name[i],surname[i] = get_name_surname(partners[i])
        partners = [None,None]
        partners_created = [None,None]
        gender = [FEMALE,MALE]
        for i in [0,1]:        
            partners[i],partners_created[i] = Skater.objects.get_or_create(
                                            name=name[i],
                                            surname=surname[i],
                                            gender=gender[i]
                                        )

         partnership, created = Partnership.objects.get_or_create(
                                    female_partner=partners[0],
                                    male_partner=partners[1],
                                )
         return partnership
问题回答

It looks like you need to subclass AutoCompleteSelectField from ajax-selects and override its clean method.

def clean(self, value):
    if value:
        lookup = get_lookup(self.channel)
        objs = lookup.get_objects( [value] )
        if objs:
            return objs[0]
        else:
            firstname, surname = value.split(" ")
            gender = self.channel.split("_")[0]
            new_skater = Skater(name=firstname, surname=surname, gender=gender)
            return new_skater
    else:
        if self.required:
            raise forms.ValidationError(self.error_messages[ required ])
        return None

Could we see what your form looks like? I think you need to so something like override the save() method in your ModelForm, so it saves the female_partner and male_partner first, then saves the form instance (aka Parntership instance).





相关问题
How to get two random records with Django

How do I get two distinct random records using Django? I ve seen questions about how to get one but I need to get two random records and they must differ.

Moving (very old) Zope/Plone Site to Django

I am ask to move data from a (now offline) site driven by Plone to a new Django site. These are the version informations I have: Zope Version (unreleased version, python 2.1.3 ) Python Version 2.1....

Can Django models use MySQL functions?

Is there a way to force Django models to pass a field to a MySQL function every time the model data is read or loaded? To clarify what I mean in SQL, I want the Django model to produce something like ...

Flexible pagination in Django

I d like to implement pagination such that I can allow the user to choose the number of records per page such as 10, 25, 50 etc. How should I go about this? Is there an app I can add onto my project ...

is it convenient to urlencode all next parameters? - django

While writing code, it is pretty common to request a page with an appended "next" query string argument. For instance, in the following template code next points back to the page the user is on: &...

Pragmatically adding give-aways/freebies to an online store

Our business currently has an online store and recently we ve been offering free specials to our customers. Right now, we simply display the special and give the buyer a notice stating we will add the ...

热门标签