是否有任何简单的机制来覆盖单元测试的Django设置?我在我的一个模型上有一个管理器,它返回特定数量的最新对象.它返回的对象数由NUM_LATEST设置定义.
如果有人要更改设置,这有可能使我的测试失败.如何覆盖设置setUp()并随后将其恢复tearDown()?如果那是不可能的,有什么方法可以修补方法或模拟设置?
编辑:这是我的经理代码:
class LatestManager(models.Manager):
"""
Returns a specific number of the most recent public Articles as defined by
the NEWS_LATEST_MAX setting.
"""
def get_query_set(self):
num_latest = getattr(settings, 'NEWS_NUM_LATEST', 10)
return super(LatestManager, self).get_query_set().filter(is_public=True)[:num_latest]
Run Code Online (Sandbox Code Playgroud)
管理器用于settings.NEWS_LATEST_MAX切片查询集.如果getattr()设置不存在,则仅用于提供默认值.
我正试图在另一个中获取模型对象实例.我提出这个错误:
Manager isn't accessible via topic instance
Run Code Online (Sandbox Code Playgroud)
这是我的模特:
class forum(models.Model):
# Some attributs
class topic(models.Model):
# Some attributs
class post(models.Model):
# Some attributs
def delete(self):
forum = self.topic.forum
super(post, self).delete()
forum.topic_count = topic.objects.filter(forum = forum).count()
Run Code Online (Sandbox Code Playgroud)
这是我的观点:
def test(request, post_id):
post = topic.objects.get(id = int(topic_id))
post.delete()
Run Code Online (Sandbox Code Playgroud)
我得到:
post.delete()
forum.topic_count = topic.objects.filter(forum = forum).count()
Manager isn't accessible via topic instances
Run Code Online (Sandbox Code Playgroud) 我正试图找到一种方法来实现自定义QuerySet和自定义Manager而不会破坏DRY.这是我到目前为止:
class MyInquiryManager(models.Manager):
def for_user(self, user):
return self.get_query_set().filter(
Q(assigned_to_user=user) |
Q(assigned_to_group__in=user.groups.all())
)
class Inquiry(models.Model):
ts = models.DateTimeField(auto_now_add=True)
status = models.ForeignKey(InquiryStatus)
assigned_to_user = models.ForeignKey(User, blank=True, null=True)
assigned_to_group = models.ForeignKey(Group, blank=True, null=True)
objects = MyInquiryManager()
Run Code Online (Sandbox Code Playgroud)
这很好,直到我做这样的事情:
inquiries = Inquiry.objects.filter(status=some_status)
my_inquiry_count = inquiries.for_user(request.user).count()
Run Code Online (Sandbox Code Playgroud)
这会立即打破一切,因为QuerySet它没有相同的方法Manager.我已经尝试创建一个自定义QuerySet类,并在其中实现它MyInquiryManager,但我最终复制了所有的方法定义.
我也发现这个片段有效,但我需要传递额外的参数,for_user因此它会因为重新定义而严重依赖get_query_set.
有没有办法在不重新定义子类QuerySet和Manager子类中的所有方法的情况下执行此操作?
我有一个自定义经理.我想将它用于相关对象.我在docs中找到了 use_for_related_fields.但它不像我使用它的方式工作:
class RandomQueryset(models.query.QuerySet):
def randomize(self):
count = self.count()
random_index = random.randint(0, count - 1)
return self.all()[random_index]
class RandomManager(models.Manager):
use_for_related_fields = True
def get_query_set(self):
return RandomQueryset(self.model, using=self._db)
def randomize(self):
return self.get_query_set().randomize()
Run Code Online (Sandbox Code Playgroud)
我用它作为一个型号:
>>> post = PostPages.default_manager.filter(image_gallery__isnull=False).distinct().randomize()
Run Code Online (Sandbox Code Playgroud)
并试图对m2m相关对象做同样的事情:
>>> post.image_gallery.randomize()
Run Code Online (Sandbox Code Playgroud)
出了错误:
AttributeError: 'ManyRelatedManager' object has no attribute 'randomize'
Run Code Online (Sandbox Code Playgroud)
是否可以像我一样使用自定义管理器?如果是这样,你如何使它工作?
我的模特:
class ShivaImage(models.Model, ImageResizing):
image = models.ImageField(upload_to='img')
slide_show = models.BooleanField()
title = models.CharField(max_length=100)
text = models.TextField(max_length=400)
ordering = models.IntegerField(blank=True, null=True)
objects = RandomManager()
class PostPages(models.Model):
image_gallery = models.ManyToManyField(ShivaImage, blank=True,
related_name='gallery',) …Run Code Online (Sandbox Code Playgroud) 我经常看到像这样的结构
MyModel.objects.all().filter(...)
Run Code Online (Sandbox Code Playgroud)
这将返回默认Mananger的QuerySet.起初all()似乎是多余的,因为
MyMode.objects.filter(...)
Run Code Online (Sandbox Code Playgroud)
提供相同的结果.
但是,这对于默认的Manager似乎是安全的,因为Django文档中有以下两个语句:
摘自"添加额外管理器方法"一章
自定义Manager方法可以返回您想要的任何内容.它不必返回QuerySet.
all()经理方法的定义:
all()返回当前QuerySet(或QuerySet子类)的副本.这在您可能希望传入模型管理器或QuerySet并对结果进行进一步过滤的情况下非常有用.在任一对象上调用all()之后,你肯定会有一个QuerySet来使用.
这似乎有点像我的矛盾.一方面,Django提供了让管理器方法返回任何首选对象类型的自由,另一方面它需要一个QuerySet用于该all()方法.我知道每个经理都有一个get_queryset被调用的方法all().但谁阻止我压倒all()我的自定义经理?虽然我同意这样做是不好的设计.
所以据我所知,该all()方法不保证返回QuerySet.到底是什么MyModel.objects回报?这句话是否要求all()?还是`get_queryset()?
你喜欢MyModel.objects.filter(...)还是MyModel.objects.all().filter(...).如果是这样,为什么?
您是否曾遇到过那些会以不合需要的方式搞乱这些方法的经理?
我在Django中有两个模型.第一个是工作职能(职位)报告到哪些其他职位的层次结构,第二个是人员和他们持有的工作职能.
class PositionHierarchy(model.Model):
pcn = models.CharField(max_length=50)
title = models.CharField(max_length=100)
level = models.CharField(max_length=25)
report_to = models.ForeignKey('PositionHierachy', null=True)
class Person(model.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
...
position = models.ForeignKey(PositionHierarchy)
Run Code Online (Sandbox Code Playgroud)
当我有人员记录并且我想找到该人的经理时,我必须这样做
manager = person.position.report_to.person_set.all()[0]
# Can't use .first() because we haven't upgraded to 1.6 yet
Run Code Online (Sandbox Code Playgroud)
如果我找到一个人QuerySet,我可以加入(并避免第二次访问数据库)使用position和report_to using Person.objects.select_related('position', 'position__reports_to').filter(...),但有没有办法避免再次访问数据库以获取person_set?我尝试添加'position__reports_to__person_set'或刚刚position__reports_to__person到select_related,但是这似乎并没有更改查询.这prefetch_related是为了什么?
我想创建一个自定义管理器,这样当我进行查询以获取Person记录时,我也会获得他们的PositionHeirarchy和他们的经理的Person记录,而不会再往返数据库.这是我到目前为止:
class PersonWithManagerManager(models.Manager):
def get_query_set(self):
qs = super(PersonWithManagerManager, self).get_query_set()
return qs.select_related(
'position',
'position__reports_to',
).prefetch_related(
)
Run Code Online (Sandbox Code Playgroud) django django-models django-queryset django-managers django-1.5
我想覆盖自定义对象模型管理器,只返回特定用户创建的对象.管理员用户仍应使用对象模型管理器返回所有对象.
现在我找到了一种可行的方法.他们建议创建自己的中间件,如下所示:
#### myproject/middleware/threadlocals.py
try:
from threading import local
except ImportError:
# Python 2.3 compatibility
from django.utils._threading_local import local
_thread_locals = local()
def get_current_user():
return getattr(_thread_locals, 'user', None)
class ThreadLocals(object):
"""Middleware that gets various objects from the
request object and saves them in thread local storage."""
def process_request(self, request):
_thread_locals.user = getattr(request, 'user', None)
#### end
Run Code Online (Sandbox Code Playgroud)
在自定义管理器中,您可以调用该get_current_user()方法仅返回特定用户创建的对象.
class UserContactManager(models.Manager):
def get_query_set(self):
return super(UserContactManager, self).get_query_set().filter(creator=get_current_user())
Run Code Online (Sandbox Code Playgroud)
这是一个很好的方法来处理这个用例吗?这会有用吗?或者这就像"使用大锤破解坚果"?;-)
只是使用:
Contact.objects.filter(created_by= user)
Run Code Online (Sandbox Code Playgroud)
在每个视图中看起来都不是很整洁.
经过一段时间的测试后,这种方法表现得相当奇怪,通过这种方法,您可以将全局状态与当前请求混合在一起.
使用下面介绍的方法.它非常简单,无需乱搞中间件. …
我想知道是否有可能(以及如果是这样,如何)将多个经理链接在一起以生成受两个经理影响的查询集.我将解释我正在研究的具体示例:
我有多个抽象模型类,用于为其他模型提供小的特定功能.其中两个模型是DeleteMixin和GlobalMixin.
DeleteMixin定义如下:
class DeleteMixin(models.Model):
deleted = models.BooleanField(default=False)
objects = DeleteManager()
class Meta:
abstract = True
def delete(self):
self.deleted = True
self.save()
Run Code Online (Sandbox Code Playgroud)
基本上它提供了伪删除(删除标志)而不是实际删除对象.
GlobalMixin定义如下:
class GlobalMixin(models.Model):
is_global = models.BooleanField(default=True)
objects = GlobalManager()
class Meta:
abstract = True
Run Code Online (Sandbox Code Playgroud)
它允许将任何对象定义为全局对象或私有对象(例如公共/私有博客帖子).
这两个都有自己的管理器,会影响返回的查询集.我的DeleteManager过滤查询集只返回已删除标志设置为False的结果,而GlobalManager过滤查询集只返回标记为全局的结果.以下是两者的声明:
class DeleteManager(models.Manager):
def get_query_set(self):
return super(DeleteManager, self).get_query_set().filter(deleted=False)
class GlobalManager(models.Manager):
def globals(self):
return self.get_query_set().filter(is_global=1)
Run Code Online (Sandbox Code Playgroud)
所需的功能是让模型扩展这两个抽象模型,并授予仅返回非删除和全局结果的能力.我在一个包含4个实例的模型上运行了一个测试用例:一个是全局的,未删除的,一个是全局的,已删除,一个是非全局的,未删除,一个是非全局的,已删除.如果我尝试获取结果集:SomeModel.objects.all(),我得到实例1和3(两个未删除的 - 很棒!).如果我尝试SomeModel.objects.globals(),我会得到一个错误,即DeleteManager没有全局变量(假设我的模型声明是这样的:SomeModel(DeleteMixin,GlobalMixin).如果我颠倒顺序,我不会得到错误,但它不会过滤掉已删除的错误).如果我更改GlobalMixin以将GlobalManager连接到全局而不是对象(因此新命令将是SomeModel.globals.globals()),我得到实例1和2(两个全局变量),而我的预期结果只是获取实例1(全局,未删除的).
我不确定是否有人遇到过与此类似的任何情况并且已经得出结果.无论是在我当前的想法中使其工作的方式还是提供我所追求的功能的重新工作都将非常感激.我知道这篇文章有点啰嗦.如果需要更多解释,我很乐意提供.
编辑:
我已经在下面发布了我用于此特定问题的最终解决方案.它基于Simon自定义QuerySetManager的链接.
这是一个非常简单的django模式问题.我的经理代码通常存在于models.py中,但是当models.py非常庞大时会发生什么?是否有任何其他替代模式可让您的经理代码在models.py中生存,以实现可维护性并避免循环导入?
可能会问一个问题,为什么models.py是如此巨大,但让我们假设它的大小和实用性的广度是合理的.
django ×10
django-managers ×10
python ×4
django-orm ×2
django-1.5 ×1
instances ×1
orm ×1
settings ×1
testing ×1