python - 更新多对多关系
问题描述
我有 3 个模型(简化):
class Product(models.Model):
category = models.ForeignKey('Category', related_name='products', to_field='category_name')
brand = models.ForeignKey('Brand', related_name='products', to_field='brand_name')
class Brand(models.Model):
brand_name = models.CharField(max_length=50)
categories = models.ManyToManyField('Category', related_name='categories')
class Category(models.Model):
category_name = models.CharField(max_length=128)
我想将管理中的类别更改为一堆产品,我为此编写了一个自定义管理功能。之后,我需要更新Brand-Categories
多对多关系以检查它Category
是否仍可用于特定的Brand
. 我写了这个函数:
def brand_refresh():
brands = Brand.objects.all().prefetch_related('shops', 'categories')
products = Product.objects.select_related('shop', 'brand', 'category')
for brand in list(brands):
for category in brand.categories.all():
if not products.filter(category=category).exists():
brand.categories.remove(category)
for product in list(products.filter(brand=brand).distinct('category')):
if product.category not in [None, category]:
brand.categories.add(product.category)
在我看来,这个怪物正在工作,但循环所有周期需要 2 小时(我有 ~220k 产品、4k+ 品牌和 ~500 个类别)。我有什么更好的方法来更新 M2M 关系吗?我认为.prefetch_related()
应该在这里有所帮助,但我现在所拥有的似乎没有效果。
解决方案
这是循环第一部分的解决方案:
您应该在数据库的一次性本地副本上尝试此操作,并在生产中运行它们之前检查一切是否正常:
from django.db.models import Count
# get a list of all categories which have no products
empty_categories = Category.objects.annotate(product_count=Count('products')).filter(product_count=0).values_list('id', flat=True)
# delete association of empty categories in all brands
Brand.categories.through.objects.filter(category_id__in=list(empty_categories)).delete()
对于第二部分,也许你可以做这样的事情,虽然我不相信它是否更快(甚至是正确的):
for brand in Brand.objects.all():
# get a list of categories of all products in the brand
brand_product_categories = brand.products.all().value_list('category__id', flat=True).distinct()
# get the brand's categories
brand_categories = Category.objects.filter(category__brand=brand).value_list('id', flat=True)
# get elements from a not in b
categories_to_add = set(brand_product_categories) - set(brand_categories)
for category_id in categories_to_add:
brand.categories.add(category_id)
推荐阅读
- opencv - 无法使用 Yolo.v3 从 lg-simulator 检测图像中的对象
- javascript - 使用 window.location 设置样式
- python-3.x - 在python中插入NULL会出错
- javascript - 反应.js | 通过道具样式与编写 CSS-in-JS
- javascript - ./src/App.js 第 6:19 行:“组件”未定义 no-undef
- python - Python将字符串列表转换为整数列表
- javascript - 使用 JS/jQuery 将 tabindex 附加到输入标签
- javascript - Fullcalendar - 来自外部文件的 JSON 数据问题
- javascript - 如何将均匀渐变应用于(particule.js)画布?
- javascript - 将 SameSite 属性添加到 Passport.js 会话 Cookie