0

I'm trying to create an instance of "Partita" Model but I don't want to set manually the fields with a form; I need to set the fields (they are two ForeignKey) with a random integer that refers to the id of the Foreign Key.

This is for create a type of creator of football matches where "Partita" (match in italian) is composed by team1 and team2 (in my code "casa" and "trasferta") How can I do it?

I tried this but it throws: Page Not Found, No FantaSquadra matches the given query.

views.py:

def createPartite(request):
    num1=0
    num2=0
    gior=0

    while num1==num2:
        num1 = str(random.randint(1,3))
        num2 = str(random.randint(1,3))
        if num1!=num2:
            gior=gior+1
    cas= get_object_or_404(FantaSquadra, pk=num1)
    tra= get_object_or_404(FantaSquadra, pk=num2)
    partita = Partita.creaP(cas,tra)
    partita.save()
    contesto = {
        'partita': partita
    }

    return render(request, 'sondaggio/partite.html',contesto)

models.py:

class FantaSquadra(models.Model):
    proprietario = models.ForeignKey(User, on_delete=models.CASCADE,unique=True)
    nome_fantasquadra = models.CharField(max_length=200,unique = True)
    punteggio = models.IntegerField(default=0)
    def __str__(self):
        return self.nome_fantasquadra

class Partita(models.Model):
    giornata = models.IntegerField(default=1)
    casa=models.ForeignKey(FantaSquadra,on_delete=models.CASCADE, related_name='fantasquadra_casa', unique=True)

    traferta = models.ForeignKey(FantaSquadra, on_delete=models.CASCADE, related_name='fantasquadra_trasferta', unique=True)
    def __str__(self):
        return "giornata "+str(self.giornata)
    def creaP(self,cas,trasfert):
        self.casa = cas
        self.traferta = trasfert
        return self
9
  • Please fix your code indentation. In Python, badly indented code is BROKEN (non executable) code (downvoted, will undownvote when code will be fixed). Commented Feb 15, 2019 at 9:12
  • Sorry, I'm not very practical about StackOverflow Commented Feb 15, 2019 at 9:24
  • 1
    What is confusing you about the error? You clearly don't have FantaSquadra instances with IDs 1 or 2. Commented Feb 15, 2019 at 9:30
  • @DanielRoseman you have right, the ID are 11 and 12 (1 and 2 don't exist), now I fixed it with the correct IDs and now it throws another error (the comment under the answer of bruno desthuilliers) Commented Feb 15, 2019 at 9:55
  • What's the point of that creaP method though? It doesn't do anything useful. In particular, despite the name it doesn't actually create a Partita. You should just do it directly in the view: Partita.objects.create(casa=cas, traferta=tra). Commented Feb 15, 2019 at 10:00

1 Answer 1

3

First (partly unrelated but not totally), you shouldn't use get_object_or_404() here. This function is just an easy shortcut for a recursive code pattern in detail views (trying to get the model instance and returning a 404 HTTP response if not found). The proper way to retrieve a model instance is YourModel.objects.get(pk=xxx), which will raise a YourModel.DoesNotExist exception if no matching record is found.

Second point (partly unrelated too but well), your view should only accept POST requests - a GET request MUST NOT modify the server state.

Now wrt/ your question: you can of course only use existing FantaSquadra records, and nothing garantees that your random numbers will match existing pks. You could solve it the brute force way:

while True:
    num = random.randint(1,3)
    try:
        obj = FantaSquadra.objects.get(pk=num)
        break
    except FantaSquadra.DoesNotExist:
        continue

but that would be very inefficient. A much simpler solution is to pick a random pk from the list of existing FantaSquadra pks:

 pks = list(FantaSquadra.objects.values_list("pk", flat=True))
 num = random.choice(pks)
 # now you're garanteed to have a matching object
 obj = FantaSquadra.objects.get(pk=num)

As an added bonus, you can now restrict the potential candidates by filtering your queryset before picking a record.

EDIT:

Also, your Partita.creaP() method is plain wrong - it doesn't "create" anything, it only updates the casa and traferta attributes of the current Partita instance (and doesn't save it). It's also useless since Django querysets already provides a method to create (really create) a new record, named, very surprisingly, 'create()`:

  partita = Partita.objects.create(casa=cas,traferta=tra)

As to the error message you got: your creaP() method is an instance method, so it's supposed to be called on an instance (in which case Python will automagically pass the instance on which you called the method as the first ('self') argument), not on the class. Well, you can call it on the class too but you then have to explicitely pass a Partita instance - which means you have to first create one. Just passing a name that has not been defined before can only lead to a NameError obviously.

Please take no offense but it looks like you don't really understand what you're doing and just try anything until it seems to work. This approach to programming is a well known antipattern and, really, it does not work. I kindly suggest that you take some time to learn Python (doing the official tutorial + browsing the doc) and Django (idem), this will save you a lot of time and pain.

Sign up to request clarification or add additional context in comments.

4 Comments

I tried your solution and now it tells me: creaP() missing 1 required positional argument: 'trasfert'. But I didn't change the function or the line where I call the function.
@doduz my code snippet was just an example of how to get ONE random record, you of course have to adapt it to your own need.
I found the mistake: the creaP function has 3 parameters (self, cas, trasfert) and when i call the function i pass only two argument (cas,tra). I tried to fix it put another parameter ( partita = Partita.creaP(partita,cas,tra) ) and now i have another error: local variable 'partita' referenced before assignment
This is another issue so it should be another question but I addressed it anyway, cf my edited answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.