在Django中将queryset合并为单个字符串
假设我有一个非常简单的模型,就是一串单词:
class WordList(models.Model):
word = models.CharField(max_length=60)
当用户提交一个表单后,我想要...
- 随机获取四个单词
- 把它们组合成一个字符串
- 确保这个字符串之前没有生成过,如果有,就再来一次
- 如果没问题,就把它保存到数据库里
- 把结果返回给用户。
我知道怎么获取四个随机单词:
WordList.objects.order_by('?')[:4]
我知道怎么把这个放到上下文中,并返回给模板,这样我就可以随意处理它,但我不知道怎么在后台完成这些操作,以便在返回给用户之前做好其他事情。最终的字符串应该是这样的:
these-are-my-words
另外,我应该在我的应用程序的哪个地方做这些呢?我之前用PHP的时候,会有一个 functions.php
文件来处理后台的事情,把它和展示部分分开。我看到有些人提到他们使用 functions.py
,但我不太确定怎么引入不在同一文件夹里的外部页面,比如和现有的 views.py
不在一个文件夹。如果我这样做:
from functions import myfunc
只有当 functions.py
和我从中导入的文件在同一个文件夹时,它才会工作。
4 个回答
最后我找到了解决办法。关键是我没意识到,QuerySet可以像访问Python列表那样直接访问。
dbQuery = WordList.objects.order_by('?')[:4]
result = dbQuery[0]
for word in dbQuery[1:]:
result = "%s-%s" % (result, word)
我觉得应该有更好的方法来做到这一点。按照建议使用的连接方法并没有奏效,我总是收到一个错误提示,说明它期待一个字符串,尽管所有文档都说这个方法是用来连接列表,而不是字符串,所以我不太明白问题出在哪里。
虽然你提供的解决方案“可以用”,但这是一种很PHP的做法。
更符合Django风格的方法是:
在你应用的models.py文件里:
from django.db import models
class Word(models.Model):
word = models.CharField(max_length=60, blank=False, null=False, unique=True)
def __unicode__(self):
return u'%s' % self.word
class RandomWordString(models.Model):
string = models.CharField(max_length=255, blank=False, null=False, unique=True)
def __unicode__(self):
return u'%s' % self.string
@staticmethod
def generate(length):
words = Word.objects.order_by('?')[:(length + 1)]
possible_word_string = '-'.join(words.values_list('word', flat=True))
try:
RandomWordString.objects.get(string=possible_word_string) # See if we've already generated this sequence
return RandomWordString.generate(length) # Call ourselves again if we have
except RandomWordString.DoesNotExist:
return possible_word_string # If we haven't, return the value
def save(self, *args, **kwargs):
if not self.string or len(self.string) < 1:
self.string = RandomWordString.generate(3)
super(RandomWordString, self).save(*args, **kwargs)
然后,从任何视图或者其他地方:
from words.models import RandomWordString
seq = RandomWordString.generate(3)
因为我们重写了保存功能,所以我们也可以直接这样做:
from words.models import RandomWordString
string = RandomWordString.objects.create()
string.save()
这样所有的逻辑都放在模型里面,这比把逻辑放在视图里要稍微好一点(不过这完全是个人喜好问题)。
除了我提到的内容,你还需要在RandomWordString.generate里加一些逻辑,以确保不会无限循环。
要把你的查询结果变成一个字符串,可以使用Python的join函数。
your_string = '-'.join([str(i) for i in WordList.objects.order_by('?')[:4]])
我觉得这段代码应该放在你的视图里,而不是直接操作数据库,不过这要看你的应用具体在做什么才好说。(你肯定是把这个字符串传给模板,然后渲染到一个HTML页面上,对吧?)