Невозможно сделать это в одном запросе. Вы должны искать документ в первом запросе:
Если существует документ:
db.bar.update( {user_id : 123456 , "items.item_name" : "my_item_two" } ,
{$inc : {"items.$.price" : 1} } ,
false ,
true);
Else
db.bar.update( {user_id : 123456 } ,
{$addToSet : {"items" : {'item_name' : "my_item_two" , 'price' : 1 }} } ,
false ,
true);
Не нужно добавлять условие {$ne : "my_item_two" }
.
Также в многопоточной среде вы должны быть осторожны, чтобы только один поток мог выполнить второй (вставить регистр, если документ не был найден) за раз, в противном случае будут вставлены дублирующие вложенные документы.
Вы можете определить поле пользовательской модели, полученное из models.CharField
. Это поле может проверять дубликаты значений, игнорируя регистр.
Документация по настраиваемым полям находится здесь http://docs.djangoproject.com/en/dev/howto/custom-model-fields/
Посмотрите на http: / /code.djangoproject.com/browser/django/trunk/django/db/models/fields/files.py для примера того, как создать настраиваемое поле путем создания подкласса существующего поля.
Вы можете использовать модуль citext в PostgreSQL https://www.postgresql.org/docs/current/static/citext.html
Если вы используете этот модуль, Пользовательское поле может определять «db_type» как CITEXT для баз данных PostgreSQL.
Это привело бы к нечувствительному к регистру сравнению уникальных значений в настраиваемом поле.
Со стороны Postgres функциональный уникальный индекс позволит вам применять уникальные значения без регистра. Также отмечается citext, но он будет работать со старыми версиями PostgreSQL и в целом полезен.
Пример:
# create table foo(bar text);
CREATE TABLE
# create unique index foo_bar on foo(lower(bar));
CREATE INDEX
# insert into foo values ('Texas');
INSERT 0 1
# insert into foo values ('texas');
ERROR: duplicate key value violates unique constraint "foo_bar"
Помимо уже упомянутой опции переопределения сохранения, вы можете просто сохранить весь текст в нижнем регистре в базе данных и использовать его для своей выгоды при отображении.
class State(models.Model):
name = models.CharField(max_length=50, unique=True)
def save(self, force_insert=False, force_update=False):
self.name = self.name.lower()
super(State, self).save(force_insert, force_update)
Решение от suhail работало для меня без необходимости включать citext, довольно простое решение, только чистая функция и вместо заглавных букв я использовал upper()
. Решение Маюреша также работает, но изменило поле с CharField
на TextField
.
class State(models.Model):
name = models.CharField(max_length=50, unique=True)
def clean(self):
self.name = self.name.upper()
Вы можете сделать это, перезаписав метод сохранения модели - см. docs . В основном вы бы сделали что-то вроде:
class State(models.Model):
name = models.CharField(max_length=50, unique=True)
def save(self, force_insert=False, force_update=False):
if State.objects.get(name__iexact = self.name):
return
else:
super(State, self).save(force_insert, force_update)
Кроме того, я могу ошибаться в этом, но предстоящая ветвь SoC для проверки модели позволит нам сделать это проще.