Джанго Формы с get_or_create - PullRequest
       13

Джанго Формы с get_or_create

22 голосов
/ 19 февраля 2010

Я использую Django ModelForms для создания формы.У меня настроена форма, и она работает нормально.

form = MyForm(data=request.POST)

if form.is_valid():
    form.save()

Теперь я хочу, чтобы форма сначала проверила, существует ли идентичная запись.Если это так, я хочу, чтобы он получил идентификатор этого объекта, а если нет, я хочу, чтобы он вставил его в базу данных, а затем дал мне идентификатор этого объекта.Это возможно, используя что-то вроде:

form.get_or_create(data=request.POST)

Я знаю, что мог бы сделать

form = MyForm(instance=object)

при создании формы, но это не сработало бы, так как я все еще хочу иметь случай, когданет экземпляра объекта

edit:

Скажите, что моя модель

class Book(models.Model):
    name = models.CharField(max_length=50)
    author = models.CharField(max_length=50)
    price = models.CharField(max_length=50)

Я хочу форму, которую кто-то может заполнить для хранения книг.Однако, если в базе данных уже есть книга с таким же именем, автором и ценой, я, очевидно, не хочу, чтобы эта запись добавлялась снова, поэтому просто хочу узнать ее идентификатор и не добавлять ее.

Я знаюв Django есть функция;get_or_create, который делает это, но есть ли что-то похожее для форм?или я должен был бы сделать что-то вроде

if form.is_valid(): 
    f = form.save(commit=false)
    id = get_or_create(name=f.name, author=f.author, price=f.price)

Спасибо

Ответы [ 5 ]

31 голосов
/ 15 октября 2010

Мне нравится такой подход:

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

Таким образом, вы получаете все преимущества форм моделей (кроме .save ()) и ярлыка get_or_create.

1 голос
/ 20 февраля 2010

Что вы подразумеваете под "если существует идентичная запись"?Если это простая проверка идентификатора, то ваш код представления будет выглядеть примерно так:

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()

Суть в том, что проверка происходит по запросу GET, так что при сохранении POST Djangoопределили, является ли это новой или существующей записью.

Если проверка идентичной записи является более сложной, может потребоваться немного изменить логику.

1 голос
/ 19 февраля 2010

Вам просто нужно два случая в представлении, прежде чем произошла обратная передача, что-то вроде

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

тогда вы можете вызвать form.save () в обратной передаче, а Django позаботится обо всем остальном.

0 голосов
/ 29 ноября 2016

Основываясь на ответах и ​​комментариях, мне пришлось создать другое решение для моего случая, которое включало использование unique_together в базовой модели. Вы можете также найти этот код полезным, поскольку я на самом деле сделал его довольно общим.

У меня есть собственный код в методе form.save(), который я хочу использовать для создания нового объекта, поэтому я не хочу просто не использовать вызов form.save(). Я должен поставить свой код проверки в методе form.save(), который я считаю разумным местом для этого.

У меня есть служебная функция для выравнивания итераций.

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

В ModelForm я перезаписываю validate_unique() метод:

def validate_unique(self):
    pass

Вот как выглядит мой метод сохранения:

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 голосов
/ 15 октября 2010

Я бы сделал это -

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()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...