Django error: Cannot assign "''": "" must be a "" instance

I am getting this error when adding a pair.

Cannot assign "'1'": "Pair.exchange" must be a "Exchange" instance.

models.py:

class Exchange(models.Model):
    name = models.CharField(max_length=25)
    def __str__(self) -> str:
        return f'{self.name}'

class Pair(models.Model):
    symbol = models.CharField(max_length=20)
    ask = models.FloatField()
    bid = models.FloatField()
    exchange = models.ForeignKey(Exchange, on_delete=models.PROTECT)
    created = models.DateTimeField()
    def __str__(self) -> str:
        return f'ID: {self.id} Symbol: {self.symbol} Ask: {self.ask} Bid: {self.bid} Exchange: {self.exchange}'

views.py:

def show_pair(request):
    pairs = Pair.objects.all()
    br = [str(pair) + '<br>' for pair in pairs]
    return HttpResponse(br)

def add_pair(request, symbol, ask, bid, exchange):
    pair = Pair.objects.create(symbol=symbol, ask=ask, bid=bid, exchange=exchange)
    return HttpResponsePermanentRedirect('/pair/')

urls.py:

path('pair/add/<symbol>/<ask>/<bid>/<exchange>/', views.add_pair)

I'm trying to add pairs via a link, but I get this error, what could be the problem?

As the error states you can not just pass the id of the "Exchange" model, but you must pass an instance of the model.

Option 1: Fetch the model instance and pass it

def add_pair(request, symbol, ask, bid, exchange):
    exchange_obj = Exchange.objects.get(id=exchange)
    pair = Pair.objects.create(symbol=symbol, ask=ask, bid=bid, exchange=exchange_obj)
    return HttpResponsePermanentRedirect('/pair/')

Option 2: When you create a ForeignKey field on your model django will actually create a database column called exchange_id, so you can also use that to create you "Pair".

def add_pair(request, symbol, ask, bid, exchange):
    pair = Pair.objects.create(symbol=symbol, ask=ask, bid=bid, exchange_id=exchange)
    return HttpResponsePermanentRedirect('/pair/')

As a bonus you might want to add some validation that the exchange id you are receiving is actually the correct one. You can use django's get_object_or_404 for this for example.

def add_pair(request, symbol, ask, bid, exchange):
    exchange_obj = get_object_or_404(Exchange.objects.all(), id=exchange)
    pair = Pair.objects.create(symbol=symbol, ask=ask, bid=bid, exchange=exchange_obj)
    return HttpResponsePermanentRedirect('/pair/')

As the error says, you need to provide an Exchange object, but it is more efficient to pass the exhange_id directly:

from django.shortcuts import redirect
from django.views.decorators.http import require_http_methods


@require_POST
def add_pair(request, symbol, ask, bid, exchange):
    pair = Pair.objects.create(
        symbol=symbol, ask=ask, bid=bid, exchange_id=exchange_id
    )
    return redirect('/pair/')

You probably should not work with a permanent redirect, since then the browser will next time never trigger the logic, but visit the redirect directly.


Note: A GET request is not supposed to have side-effects, hence constructing objects when a user makes a GET request, is not compliant with the HTTP standard. Therefore it might be better to turn this into a POST request.

Back to Top