Django Forms with get_or_create

前端 未结 5 951
清酒与你
清酒与你 2021-01-31 09:46

I am using Django ModelForms to create a form. I have my form set up and it is working ok.

form = MyForm(data=request.POST)

if form.is_valid():
    form.sav         


        
相关标签:
5条回答
  • 2021-01-31 10:13

    What do you mean by "if an identical record exists"? If this is a simple ID check, then your view code would look something like this:

    if request.method == 'POST':
        form = MyForm(request.POST)
        if form.is_valid():
            form.save()
    else:
        if get_id:
            obj = MyModel.objects.get(id=get_id)
            form = MyForm(instance=obj)
        else:
            form = MyForm()
    

    The concept here is the check occurs on the GET request, such that on the POST to save, Django will already have determined if this is a new or existing record.

    If your check for an identical record is more complex, it might require shifting the logic around a bit.

    0 讨论(0)
  • 2021-01-31 10:23

    I would do this -

    if request.method == 'POST':
        form = MyForm(request.POST)
        if form.is_valid():
            name   = form.cleaned_data['name']
            author = form.cleaned_data['author']
            price  = form.cleaned_data['prince']
    
            if name and author and price:
                book, created = Book.objects.get_or_create(name=name, \
                  author=author, price=price)
    
                if created:
                    # fresh entry in db.
                else:
                    # already there, maybe update?
    
                book.save()
    
    0 讨论(0)
  • 2021-01-31 10:27

    Based on the answers and comments, I had to create a different solution for my case, which included the use of unique_together on the base model. You may find this code useful as well, as I actually made it fairly generic.

    I have custom code in the form.save() method that I want to utilize for creating a new object, so I don't want to simply not use the form.save() call. I do have to put my code check in the form.save() method, which I think is a reasonable place to put it.

    I have a utility function to flatten iterables.

    def flatten(l, a=list()):
        """ 
            Flattens a list.  Just do flatten(l).
            Disregard the a since it is used in recursive calls.
        """
            for i in l:
                if isinstance(i, Iterable):
                    flatten_layout(i, a)
                else:
                    a.append(i)
            return a
    

    In the ModelForm, I overwrite the validate_unique() method:

    def validate_unique(self):
        pass
    

    This is about what my save method looks like:

    def save(self, commit=True):
        unique_fields = flatten(MyObject._meta.unique_together)
        unique_cleaned_data = {k: v for k, v in self.cleaned_data.items() if k in unique_fields}
        # check if the object exists in the database based on unique data
        try:
            my_object = MyObject.objects.get(**unique_cleaned_data)
        except MyObject.DoesNotExist:
            my_object = super(MyModelFormAjax, self).save(commit)
            # -- insert extra code for saving a new object here ---
        else:
            for data, value in self.cleaned_data.items():
                if data not in unique_fields:
                    # only update the field if it has data; otherwise, retain
                    #   the old value; you may want to comment or remove this
                    #   next line
                    if value:
                        setattr(my_object, data, value)
    
            if commit:
                my_object.save()
        return my_object
    
    0 讨论(0)
  • 2021-01-31 10:28

    You just need two cases in the view before the postback has occurred, something like

    if id:
        form = MyForm(instance=obj)
    else
        form = MyForm()
    

    then you can call form.save() in the postback and Django will take care of the rest.

    0 讨论(0)
  • 2021-01-31 10:34

    I like this approach:

    if request.method == 'POST':
        form = MyForm(request.POST)
        if form.is_valid():
           book, created = Book.objects.get_or_create(**form.cleaned_data)
    

    That way you get to take advantage of all the functionality of model forms (except .save()) and the get_or_create shortcut.

    0 讨论(0)
提交回复
热议问题