应该如何将模型对象传递给Django中的辅助函数

时间:2017-10-05 12:11:54

标签: python django django-models

在Django中将模型对象传递给辅助函数的正确方法是什么?

例如,我有一个用户对象:

u = User.objects.get(pk=1)  

然后想要在保存回DB之前使用函数uhelpers.foo()上执行一些操作。

我应该通过整个对象并直接操作吗?或者只是ID然后在辅助函数中重新查询数据库以再次获取对象...

3 个答案:

答案 0 :(得分:2)

让我们做一点测试:

>>> from django.contrib.auth.models import User
>>> u1 = User.objects.get(pk=1)
>>> u2 = User.objects.get(pk=1)
>>> u1 == u2
True
>>> u1 is u2
False
>>> u1.first_name
u'Ruth'
>>> u2.first_name
u'Ruth'
>>> u2.first_name = u"Route"
>>> u2 == u1
True
>>> u1.first_name
u'Ruth'
>>> u2.save()
>>> u1.first_name
u'Ruth'
>>> 
>>> u1.refresh_from_db()
>>> u1.first_name
u'Route'

正如您所看到的,两次加载相同的记录会产生两个不同的对象(它们相等,因为Model在pk上进行比较),而更改一个 - 无论是否保存更改 - 都不会影响第二个(直到你从db中刷新它当然)。此外,如果您修改并保存两者,结果可能与预期不符:

>>> u1.last_name
u'FOOBAR'
>>> u2.last_name
u'FOOBAR'
>>>
>>> u1.first_name = u"Ruth"
>>> u2.last_name = u"ROOTZ"
>>> u1.save()
>>> u2.save()
>>> ux = User.objects.get(pk=1)
>>> ux.first_name
u'Route'
>>> ux.last_name
u'ROOTZ'

如果考虑数据库访问成本,很明显您不希望让辅助函数从数据库加载第二个(不同的)实例。

异步调用(通常是芹菜任务)的情况不同 - 在这里你要传递对象的id并让你的任务从数据库重新加载它。主要原因是数据库记录migh在任务调用和执行之间被修改(并且您不想覆盖这些修改)。

答案 1 :(得分:0)

传递完整对象的更好方法,如果只传递id,则必须再次点击数据库以获取用户。

答案 2 :(得分:0)

如果你一般都在询问,我已经将一个工作项目的一部分添加到底部。但是,在您的情况下,我相信您可以定义一个实例方法来处理所选对象 - 当然,如果这些操作与模型直接相关。

class User(models.Model):
    first_name = models.CharField(max_length=40)
    last_name = models.CharField(max_length=40)
    title = models.CharField(max_length = 50)
    ...

    def make_comrade(self):
        return "Comrade " + self.last_name

然后,

user = User.objects.get(pk=1)
user.update(title=user.make_comrade())

我上面已经说过的代码。

在我的 views.py

from reports_helper import report_generator

...

def export_terminals_daily_turnover(request):
    return report_generator('TerminalTurnover', 'daily_turnover', 'terminal_id', 'address_on_bill', 'summ')

这是我的 reports_helper.py

import csv
import django
from django.http import  HttpResponse


def get_model_name(model_name):
    entity = django.apps.apps.get_model('reports', model_name)
    return entity


def report_generator(model_name, report_name, *args):
    response = HttpResponse(content_type='text/csv')
    response['Content-Disposition'] = 'attachment; filename="{}.csv"'.format(report_name)

    headers = list(args)
    klass = get_model_name(model_name)

    writer = csv.writer(response)
    writer.writerow(headers)

    rows = klass.objects.all().values_list(*args)
    for row in rows:
        writer.writerow(row)

    return response
不过,我所指的模型是db视图而不是表

class TerminalTurnover(models.Model):
    terminal_id = models.IntegerField(primary_key=True)
    summ = models.DecimalField(max_digits=15, decimal_places=2)
    address_on_bill = models.CharField(max_length=100)

    class Meta:
        managed = False
        db_table = 'reports_terminalturnover'