SlugRelatedField
, предоставленный инфраструктурой Django REST, как и многие связанные с ним поля, предназначен для использования с уже существующими объектами. Поскольку вы ищете ссылку на объекты, которые уже существуют, или объект, который нужно создать, вы не сможете использовать его как есть.
Вам понадобится пользовательский SlugRelatedField
, который создает новый объект, если его не существует.
class CreatableSlugRelatedField(serializers.SlugRelatedField):
def to_internal_value(self, data):
try:
return self.get_queryset().get_or_create(**{self.slug_field: data})[0]
except ObjectDoesNotExist:
self.fail('does_not_exist', slug_name=self.slug_field, value=smart_text(data))
except (TypeError, ValueError):
self.fail('invalid')
class MerchantSerializer(serializers.ModelSerializer):
phones = CreateableSlugRelatedField(
many=True,
slug_field='phone',
queryset=primitives.Phone.objects.all()
)
class Meta:
model = Merchant
fields = (
'merchant_id',
'name',
'is_active',
'phones',
)
При переключении на get_or_create
объект номера телефона будет создан, если он еще не существует. Возможно, вам придется настроить его, если на модели будут созданы дополнительные поля.
Следуя решению @ TaylorWood , вы можете выразить обе свои функции более кратко, хотя я не уверен, что краткие версии так же ясны.
Ваша create-contest
функция map
проверяет каждое число i
, чтобы узнать, является ли оно одним . Лучше просто поменять на напрямую. Для этого нам нужен вектор, который, я думаю, вы все равно захотите найти при моделировании игры:
(defn create-contest [n]
(assoc (vec (repeat n :closed)) (rand-int n) :car))
Ваша функция create-doors
многократно передает один и тот же аргумент своему map
' с функцией. Вы можете использовать repeatedly
на закрытии, чтобы получить тот же эффект:
(defn create-doors [doors contests]
(repeatedly contests (partial create-contest doors)))
или
(defn create-doors [doors contests]
(repeatedly contests #(create-contest doors)))
Вы очень близки, вы должны просто использовать форму let
вместо def
здесь:
(defn create-contest
"Creates a monty hall doors contest"
[n]
(let [door-with-car (rand-int n)] ;; let instead of def
(map
(fn [i] (if (= i door-with-car) :car :closed))
(range n))))
def
свяжет некоторое значение с переменной в текущем пространстве имен, но Вы хотите связать значение в области действия этой функции, и для этого хорошо let
. См. этот Q & A для другого объяснения.
(defn create-doors
"Create a collection of monty hall contests"
[doors contests]
(map
create-contest ;; no need to wrap create-contest in another function here
(repeat contests doors)))
Вам не нужно заключать create-contest
в другую функцию для использования с map
- вы можете просто передать функцию непосредственно в map
в качестве значения. doall
необходим только для принудительной реализации отложенной последовательности из map
, поэтому вам, вероятно, не нужно / не нужно этого внутри create-doors
.
(create-doors 4 10)
=>
((:closed :closed :car :closed)
(:closed :closed :closed :car)
(:closed :car :closed :closed)
(:closed :closed :closed :car)
(:closed :car :closed :closed)
(:closed :car :closed :closed)
(:closed :car :closed :closed)
(:closed :closed :closed :car)
(:closed :closed :car :closed)
(:closed :closed :car :closed))