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

Question:

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?

Asked By: Xena

||

Answers:

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/')
Answered By: jazzyoda5

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.

Answered By: Willem Van Onsem