【问题标题】:Django create instance model without formDjango创建没有表单的实例模型
【发布时间】:2019-02-15 09:02:04
【问题描述】:

我正在尝试创建“Partita”模型的实例,但我不想使用表单手动设置字段;我需要使用一个随机整数来设置字段(它们是两个 ForeignKey),该整数引用外键的 id。

这是为了创建一种足球比赛的创建者,其中“Partita”(意大利语比赛)由 team1 和 team2(在我的代码“casa”和“trasferta”中)组成我该怎么做?

我试过了,但它抛出:页面未找到,没有 FantaSquadra 匹配给定的查询。

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

【问题讨论】:

  • 请修正您的代码缩进。在 Python 中,严重缩进的代码是 BROKEN(不可执行)代码(被否决,当代码被修复时将被取消投票)。
  • 对不起,我对 StackOverflow 不是很实际
  • 这个错误让您感到困惑的是什么?您显然没有 ID 为 1 或 2 的 FantaSquadra 实例。
  • @DanielRoseman 你说得对,ID 是 11 和 12(1 和 2 不存在),现在我用正确的 ID 修复它,现在它抛出另一个错误(答案下的评论布鲁诺·德舒利耶)
  • 那个 creaP 方法有什么意义呢?它没有做任何有用的事情。特别是,尽管有这个名字,它实际上并没有创建一个 Partita。您应该直接在视图中执行此操作:Partita.objects.create(casa=cas, traferta=tra)

标签: python django


【解决方案1】:

首先(部分不相关但不完全相关),你不应该在这里使用get_object_or_404()。此函数只是详细视图中递归代码模式的一个简单快捷方式(尝试获取模型实例并在未找到时返回 404 HTTP 响应)。检索模型实例的正确方法是YourModel.objects.get(pk=xxx),如果找不到匹配记录,它将引发YourModel.DoesNotExist 异常。

第二点(部分无关但很好),您的视图应该只接受 POST 请求 - GET 请求不得修改服务器状态。

现在 wrt/您的问题:您当然只能使用现有的 FantaSquadra 记录,并且不保证您的随机数将匹配现有的 pks。你可以用蛮力的方式解决它:

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

但这将是非常低效的。一个更简单的解决方案是从 existing FantaSquadra pk 列表中选择一个随机 pk:

 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)

作为额外的好处,您现在可以通过在选择记录之前过滤您的查询集来限制潜在的候选人。

编辑:

另外,您的 Partita.creaP() 方法是完全错误的 - 它不会“创建”任何东西,它只会更新当前 Partita 实例的 casatraferta 属性(并且不会保存它) .这也是无用的,因为 Django 查询集已经提供了一种创建(真正创建)新记录的方法,非常令人惊讶的是,它命名为 'create()`:

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

关于您收到的错误消息:您的 creaP() 方法是一个实例方法,因此应该在实例上调用它(在这种情况下,Python 会自动将您调用该方法的实例作为第一个传递( 'self') 论点),而不是在课堂上。好吧,你也可以在类上调用它,但是你必须明确地传递一个Partita 实例——这意味着你必须首先创建一个。仅仅传递一个之前未定义的名字显然只会导致NameError。

请不要冒犯,但您似乎并不真正了解自己在做什么,just try anything until it seems to work。这种编程方法是a well known antipattern,实际上,它不起作用。我建议你花一些时间学习 Python(做官方教程 + 浏览文档)和 Django(同上),这样可以节省你很多时间和痛苦。

【讨论】:

  • 我尝试了您的解决方案,现在它告诉我:creaP() 缺少 1 个必需的位置参数:'trasfert'。但我没有更改函数或调用函数的行。
  • @doduz 我的代码 sn-p 只是如何获取 ONE 随机记录的示例,您当然必须根据自己的需要进行调整。
  • 我发现了错误:creaP 函数有 3 个参数(self、cas、trasfert),当我调用该函数时,我只传递了两个参数(cas、tra)。我试图修复它放置另一个参数( partita = Partita.creaP(partita,cas,tra) ),现在我有另一个错误:在赋值之前引用局部变量 'partita'
  • 这是另一个问题,所以应该是另一个问题,但我还是解决了这个问题,参见我编辑的答案。
猜你喜欢
  • 2013-02-11
  • 1970-01-01
  • 2016-09-03
  • 2016-08-07
  • 2021-03-09
  • 1970-01-01
  • 2021-06-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多