From badc535aeb1d310a9b8aa59aade07045e6eae653 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Wed, 18 Apr 2012 15:05:43 -0500 Subject: Ensure order_by default value is cleared when using distinct() Otherwise the queryset returns nonsensical results. I find the design of this less than obvious but so be it; we can ensure the results work regardless of a default ordering on the model. Signed-off-by: Dan McGee --- main/models.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'main/models.py') diff --git a/main/models.py b/main/models.py index c532ed56..398cb88b 100644 --- a/main/models.py +++ b/main/models.py @@ -13,7 +13,7 @@ from .utils import cache_function, set_created_field, utc_now class TodolistManager(models.Manager): def incomplete(self): - return self.filter(todolistpkg__complete=False).distinct() + return self.filter(todolistpkg__complete=False).order_by().distinct() class PackageManager(models.Manager): def flagged(self): @@ -378,7 +378,7 @@ class PackageDepend(models.Model): '''Return providers of this dep. Does *not* include exact matches as it checks the Provision names only, use get_best_satisfier() instead.''' pkgs = Package.objects.normal().filter( - provides__name=self.depname).distinct() + provides__name=self.depname).order_by().distinct() if arches is not None: pkgs = pkgs.filter(arch__in=arches) @@ -432,7 +432,8 @@ class Todolist(models.Model): @property def package_names(self): # depends on packages property returning a queryset - return self.packages.values_list('pkg__pkgname', flat=True).distinct() + return self.packages.values_list( + 'pkg__pkgname', flat=True).order_by().distinct() class Meta: db_table = 'todolists' -- cgit v1.2.3-2-g168b From f6c2bc6c33bf1fe4fe4cfff4c0177fd296c3b587 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Fri, 18 May 2012 19:55:48 -0500 Subject: Simplify get_best_satisfier and get_providers We always passed values in that came off the containing package object; we can access these directly in the methods themselves. Signed-off-by: Dan McGee --- main/models.py | 51 ++++++++++++++++++++++++--------------------------- 1 file changed, 24 insertions(+), 27 deletions(-) (limited to 'main/models.py') diff --git a/main/models.py b/main/models.py index 398cb88b..4b445dd0 100644 --- a/main/models.py +++ b/main/models.py @@ -231,16 +231,12 @@ class Package(models.Model): """ deps = [] arches = None - if not self.arch.agnostic: - arches = self.applicable_arches() # TODO: we can use list comprehension and an 'in' query to make this more effective for dep in self.depends.order_by('optional', 'depname'): - pkg = dep.get_best_satisfier(arches, testing=self.repo.testing, - staging=self.repo.staging) + pkg = dep.get_best_satisfier() providers = None if not pkg: - providers = dep.get_providers(arches, - testing=self.repo.testing, staging=self.repo.staging) + providers = dep.get_providers() deps.append({'dep': dep, 'pkg': pkg, 'providers': providers}) return deps @@ -343,13 +339,14 @@ class PackageDepend(models.Model): optional = models.BooleanField(default=False) description = models.TextField(null=True, blank=True) - def get_best_satisfier(self, arches=None, testing=None, staging=None): + def get_best_satisfier(self): '''Find a satisfier for this dependency that best matches the given criteria. It will not search provisions, but will find packages named and matching repo characteristics if possible.''' pkgs = Package.objects.normal().filter(pkgname=self.depname) - if arches is not None: + if not self.pkg.arch.agnostic: # make sure we match architectures if possible + arches = self.pkg.applicable_arches() pkgs = pkgs.filter(arch__in=arches) if len(pkgs) == 0: # couldn't find a package in the DB @@ -362,42 +359,42 @@ class PackageDepend(models.Model): pkg = pkgs[0] # prevents yet more DB queries, these lists should be short; # after each grab the best available in case we remove all entries - if staging is not None: - pkgs = [p for p in pkgs if p.repo.staging == staging] + pkgs = [p for p in pkgs if p.repo.staging == self.pkg.repo.staging] if len(pkgs) > 0: pkg = pkgs[0] - if testing is not None: - pkgs = [p for p in pkgs if p.repo.testing == testing] + pkgs = [p for p in pkgs if p.repo.testing == self.pkg.repo.testing] if len(pkgs) > 0: pkg = pkgs[0] return pkg - def get_providers(self, arches=None, testing=None, staging=None): + def get_providers(self): '''Return providers of this dep. Does *not* include exact matches as it checks the Provision names only, use get_best_satisfier() instead.''' pkgs = Package.objects.normal().filter( provides__name=self.depname).order_by().distinct() - if arches is not None: + if not self.pkg.arch.agnostic: + # make sure we match architectures if possible + arches = self.pkg.applicable_arches() pkgs = pkgs.filter(arch__in=arches) # Logic here is to filter out packages that are in multiple repos if # they are not requested. For example, if testing is False, only show a # testing package if it doesn't exist in a non-testing repo. - if staging is not None: - filtered = {} - for p in pkgs: - if p.pkgname not in filtered or p.repo.staging == staging: - filtered[p.pkgname] = p - pkgs = filtered.values() - - if testing is not None: - filtered = {} - for p in pkgs: - if p.pkgname not in filtered or p.repo.testing == testing: - filtered[p.pkgname] = p - pkgs = filtered.values() + filtered = {} + for package in pkgs: + if package.pkgname not in filtered or \ + package.repo.staging == self.pkg.repo.staging: + filtered[package.pkgname] = package + pkgs = filtered.values() + + filtered = {} + for package in pkgs: + if package.pkgname not in filtered or \ + package.repo.testing == self.pkg.repo.testing: + filtered[package.pkgname] = package + pkgs = filtered.values() return pkgs -- cgit v1.2.3-2-g168b From 72a92102df4999dbcc370064707c9026d51c4fe7 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Fri, 18 May 2012 21:29:03 -0500 Subject: Switch to usage of new Depend object Signed-off-by: Dan McGee --- main/models.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'main/models.py') diff --git a/main/models.py b/main/models.py index 4b445dd0..f17d4a4d 100644 --- a/main/models.py +++ b/main/models.py @@ -180,11 +180,12 @@ class Package(models.Model): list slim by including the corresponding package in the same testing category as this package if that check makes sense. """ + from packages.models import Depend provides = set(self.provides.values_list('name', flat=True)) provides.add(self.pkgname) - requiredby = PackageDepend.objects.select_related('pkg', + requiredby = Depend.objects.select_related('pkg', 'pkg__arch', 'pkg__repo').filter( - depname__in=provides).order_by( + name__in=provides).order_by( 'pkg__pkgname', 'pkg__arch__name', 'pkg__repo__name') if not self.arch.agnostic: # make sure we match architectures if possible @@ -232,7 +233,7 @@ class Package(models.Model): deps = [] arches = None # TODO: we can use list comprehension and an 'in' query to make this more effective - for dep in self.depends.order_by('optional', 'depname'): + for dep in self.depends.order_by('optional', 'name'): pkg = dep.get_best_satisfier() providers = None if not pkg: -- cgit v1.2.3-2-g168b From e1f9a3c44a1449a36f3981b868814f3d1f65d70d Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Fri, 18 May 2012 21:35:28 -0500 Subject: Drop old PackageDepend model Signed-off-by: Dan McGee --- main/models.py | 71 ---------------------------------------------------------- 1 file changed, 71 deletions(-) (limited to 'main/models.py') diff --git a/main/models.py b/main/models.py index f17d4a4d..04d8da8f 100644 --- a/main/models.py +++ b/main/models.py @@ -333,77 +333,6 @@ class PackageFile(models.Model): class Meta: db_table = 'package_files' -class PackageDepend(models.Model): - pkg = models.ForeignKey(Package, related_name='depends') - depname = models.CharField(max_length=255, db_index=True) - depvcmp = models.CharField(max_length=255, default='') - optional = models.BooleanField(default=False) - description = models.TextField(null=True, blank=True) - - def get_best_satisfier(self): - '''Find a satisfier for this dependency that best matches the given - criteria. It will not search provisions, but will find packages named - and matching repo characteristics if possible.''' - pkgs = Package.objects.normal().filter(pkgname=self.depname) - if not self.pkg.arch.agnostic: - # make sure we match architectures if possible - arches = self.pkg.applicable_arches() - pkgs = pkgs.filter(arch__in=arches) - if len(pkgs) == 0: - # couldn't find a package in the DB - # it should be a virtual depend (or a removed package) - return None - if len(pkgs) == 1: - return pkgs[0] - # more than one package, see if we can't shrink it down - # grab the first though in case we fail - pkg = pkgs[0] - # prevents yet more DB queries, these lists should be short; - # after each grab the best available in case we remove all entries - pkgs = [p for p in pkgs if p.repo.staging == self.pkg.repo.staging] - if len(pkgs) > 0: - pkg = pkgs[0] - - pkgs = [p for p in pkgs if p.repo.testing == self.pkg.repo.testing] - if len(pkgs) > 0: - pkg = pkgs[0] - - return pkg - - def get_providers(self): - '''Return providers of this dep. Does *not* include exact matches as it - checks the Provision names only, use get_best_satisfier() instead.''' - pkgs = Package.objects.normal().filter( - provides__name=self.depname).order_by().distinct() - if not self.pkg.arch.agnostic: - # make sure we match architectures if possible - arches = self.pkg.applicable_arches() - pkgs = pkgs.filter(arch__in=arches) - - # Logic here is to filter out packages that are in multiple repos if - # they are not requested. For example, if testing is False, only show a - # testing package if it doesn't exist in a non-testing repo. - filtered = {} - for package in pkgs: - if package.pkgname not in filtered or \ - package.repo.staging == self.pkg.repo.staging: - filtered[package.pkgname] = package - pkgs = filtered.values() - - filtered = {} - for package in pkgs: - if package.pkgname not in filtered or \ - package.repo.testing == self.pkg.repo.testing: - filtered[package.pkgname] = package - pkgs = filtered.values() - - return pkgs - - def __unicode__(self): - return "%s%s" % (self.depname, self.depvcmp) - - class Meta: - db_table = 'package_depends' class Todolist(models.Model): creator = models.ForeignKey(User, on_delete=models.PROTECT) -- cgit v1.2.3-2-g168b From c0bf9e20660cfae7ea8994472555bba23398b598 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 24 Jul 2012 09:19:48 -0500 Subject: Remove custom utc_now() function, use django.utils.timezone.now() This was around from the time when we handled timezones sanely and Django did not; now that we are on 1.4 we no longer need our own code to handle this. Signed-off-by: Dan McGee --- main/models.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'main/models.py') diff --git a/main/models.py b/main/models.py index 04d8da8f..6c9dfe4d 100644 --- a/main/models.py +++ b/main/models.py @@ -6,9 +6,10 @@ from pgpdump import BinaryData from django.db import models from django.contrib.auth.models import User from django.contrib.sites.models import Site +from django.utils.timezone import now from .fields import PositiveBigIntegerField -from .utils import cache_function, set_created_field, utc_now +from .utils import cache_function, set_created_field class TodolistManager(models.Manager): @@ -385,7 +386,7 @@ class TodolistPkg(models.Model): def set_todolist_fields(sender, **kwargs): todolist = kwargs['instance'] if not todolist.date_added: - todolist.date_added = utc_now() + todolist.date_added = now() # connect signals needed to keep cache in line with reality from main.utils import refresh_latest -- cgit v1.2.3-2-g168b From 0cc369e985dd6376f0367e4b57e980ce14231796 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 31 Jul 2012 00:09:28 -0500 Subject: Update several bits and pieces for staging packages This will prevent [staging] packages from cluttering normal user's view on the website, but allow us to still import everything from this repository for developer use. Signed-off-by: Dan McGee --- main/models.py | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) (limited to 'main/models.py') diff --git a/main/models.py b/main/models.py index 6c9dfe4d..577f11c6 100644 --- a/main/models.py +++ b/main/models.py @@ -4,6 +4,7 @@ from itertools import groupby from pgpdump import BinaryData from django.db import models +from django.db.models import Q from django.contrib.auth.models import User from django.contrib.sites.models import Site from django.utils.timezone import now @@ -24,6 +25,12 @@ class PackageManager(models.Manager): def normal(self): return self.select_related('arch', 'repo') + def restricted(self, user=None): + qs = self.normal() + if user is not None and user.is_authenticated: + return qs + return qs.filter(repo__staging=False) + class Donor(models.Model): name = models.CharField(max_length=255, unique=True) visible = models.BooleanField(default=True, @@ -193,22 +200,26 @@ class Package(models.Model): requiredby = requiredby.filter( pkg__arch__in=self.applicable_arches()) # sort out duplicate packages; this happens if something has a double - # versioned dep such as a kernel module + # versioned depend such as a kernel module requiredby = [list(vals)[0] for _, vals in groupby(requiredby, lambda x: x.pkg.id)] + if len(requiredby) == 0: + return requiredby - # find another package by this name in the opposite testing setup - # TODO: figure out staging exclusions too - if not Package.objects.filter(pkgname=self.pkgname, - arch=self.arch).exclude(id=self.id).exclude( - repo__testing=self.repo.testing).exists(): + # find another package by this name in a different testing or staging + # repo; if we can't, we can short-circuit some checks + repo_q = (Q(repo__testing=(not self.repo.testing)) | + Q(repo__staging=(not self.repo.staging))) + if not Package.objects.filter( + repo_q, pkgname=self.pkgname, arch=self.arch + ).exclude(id=self.id).exists(): # there isn't one? short circuit, all required by entries are fine return requiredby trimmed = [] # for each unique package name, try to screen our package list down to - # those packages in the same testing category (yes or no) iff there is - # a package in the same testing category. + # those packages in the same testing and staging category (yes or no) + # iff there is a package in the same testing and staging category. for _, dep_pkgs in groupby(requiredby, lambda x: x.pkg.pkgname): dep_pkgs = list(dep_pkgs) dep = dep_pkgs[0] @@ -254,7 +265,7 @@ class Package(models.Model): return Package.objects.normal().get(arch=self.arch, repo=self.repo, pkgname=self.pkgbase) except Package.DoesNotExist: - # this package might be split across repos? just find one + # this package might be split across repos? find one # that matches the correct [testing] repo flag pkglist = Package.objects.normal().filter(arch=self.arch, repo__testing=self.repo.testing, @@ -271,8 +282,10 @@ class Package(models.Model): repo.testing and repo.staging flags. For any non-split packages, the return value will be an empty list. """ - return Package.objects.normal().filter(arch__in=self.applicable_arches(), - repo__testing=self.repo.testing, repo__staging=self.repo.staging, + return Package.objects.normal().filter( + arch__in=self.applicable_arches(), + repo__testing=self.repo.testing, + repo__staging=self.repo.staging, pkgbase=self.pkgbase).exclude(id=self.id) def flag_request(self): -- cgit v1.2.3-2-g168b From a64bbbd4139d91cbbca10d804067cbd87a95872d Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 31 Jul 2012 20:27:43 -0500 Subject: Make adjustments for optional -> deptype conversion Very little dealt directly with this field. Signed-off-by: Dan McGee --- main/models.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'main/models.py') diff --git a/main/models.py b/main/models.py index 577f11c6..f4ced350 100644 --- a/main/models.py +++ b/main/models.py @@ -245,13 +245,18 @@ class Package(models.Model): deps = [] arches = None # TODO: we can use list comprehension and an 'in' query to make this more effective - for dep in self.depends.order_by('optional', 'name'): + for dep in self.depends.all(): pkg = dep.get_best_satisfier() providers = None if not pkg: providers = dep.get_providers() deps.append({'dep': dep, 'pkg': pkg, 'providers': providers}) - return deps + # sort the list; deptype sorting makes this tricker than expected + sort_order = {'D': 0, 'O': 1, 'M': 2, 'C': 3} + def sort_key(val): + dep = val['dep'] + return (sort_order.get(dep.deptype, 1000), dep.name) + return sorted(deps, key=sort_key) @cache_function(125) def base_package(self): -- cgit v1.2.3-2-g168b From 8ca64af397718f7dda0080467d202c6a70a33c8c Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sun, 5 Aug 2012 11:21:59 -0500 Subject: Smarter handling of multilib packages in "Versions Elsewhere" We can do some manipulation of the pkgname to ensure multilib packages show up here, as well as showing the non-multilib versions in the list when viewing the multilib packages. Signed-off-by: Dan McGee --- main/models.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'main/models.py') diff --git a/main/models.py b/main/models.py index f4ced350..7d8ea755 100644 --- a/main/models.py +++ b/main/models.py @@ -336,8 +336,16 @@ class Package(models.Model): def elsewhere(self): '''attempt to locate this package anywhere else, regardless of architecture or repository. Excludes this package from the list.''' + names = [self.pkgname] + if self.pkgname.startswith('lib32-'): + names.append(self.pkgname[6:]) + elif self.pkgname.endswith('-multilib'): + names.append(self.pkgname[:-9]) + else: + names.append('lib32-' + self.pkgname) + names.append(self.pkgname + '-multilib') return Package.objects.normal().filter( - pkgname=self.pkgname).exclude(id=self.id).order_by( + pkgname__in=names).exclude(id=self.id).order_by( 'arch__name', 'repo__name') class PackageFile(models.Model): -- cgit v1.2.3-2-g168b From 7d9ed0b881bd05878e7a54f785c2551bc6e336d6 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 7 Aug 2012 01:16:51 -0500 Subject: Add reverse conflicts to package details This is a place where calling vercmp could come in really handy. Signed-off-by: Dan McGee --- main/models.py | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'main/models.py') diff --git a/main/models.py b/main/models.py index 7d8ea755..b49edde3 100644 --- a/main/models.py +++ b/main/models.py @@ -258,6 +258,16 @@ class Package(models.Model): return (sort_order.get(dep.deptype, 1000), dep.name) return sorted(deps, key=sort_key) + @cache_function(123) + def reverse_conflicts(self): + """ + Returns a list of packages with conflicts against this package. + """ + # TODO: fix this; right now we cheat since we can't do proper version + # number checking without using alpm or vercmp directly. + return Package.objects.filter(conflicts__name=self.pkgname, + conflicts__comparison='').distinct() + @cache_function(125) def base_package(self): """ -- cgit v1.2.3-2-g168b From f63a70f5118781fe34d82ae0d59c911f0ea28d1d Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 7 Aug 2012 19:36:07 -0500 Subject: Make use of new ctypes ALPM API We can use this when filtering down lists of depends, required by, conflicts, etc. to ensure we are honoring the version specifications the same way pacman would. Signed-off-by: Dan McGee --- main/models.py | 55 ++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 48 insertions(+), 7 deletions(-) (limited to 'main/models.py') diff --git a/main/models.py b/main/models.py index b49edde3..bb2320e8 100644 --- a/main/models.py +++ b/main/models.py @@ -11,6 +11,7 @@ from django.utils.timezone import now from .fields import PositiveBigIntegerField from .utils import cache_function, set_created_field +from packages.alpm import AlpmAPI class TodolistManager(models.Manager): @@ -189,16 +190,42 @@ class Package(models.Model): category as this package if that check makes sense. """ from packages.models import Depend - provides = set(self.provides.values_list('name', flat=True)) - provides.add(self.pkgname) + provides = self.provides.all() + provide_names = set(provide.name for provide in provides) + provide_names.add(self.pkgname) requiredby = Depend.objects.select_related('pkg', 'pkg__arch', 'pkg__repo').filter( - name__in=provides).order_by( + name__in=provide_names).order_by( 'pkg__pkgname', 'pkg__arch__name', 'pkg__repo__name') if not self.arch.agnostic: # make sure we match architectures if possible requiredby = requiredby.filter( pkg__arch__in=self.applicable_arches()) + + # if we can use ALPM, ensure our returned Depend objects abide by the + # version comparison operators they may specify + alpm = AlpmAPI() + if alpm.available: + new_rqd = [] + for dep in requiredby: + if not dep.comparison or not dep.version: + # no comparisson/version, so always let it through + new_rqd.append(dep) + elif self.pkgname == dep.name: + # depends on this package, so check it directly + if alpm.compare_versions(self.full_version, + dep.comparison, dep.version): + new_rqd.append(dep) + else: + # it must be a provision of ours at this point + for provide in (p for p in provides if p.name == dep.name): + print(provide.version, dep.comparison, dep.version) + if alpm.compare_versions(provide.version, + dep.comparison, dep.version): + new_rqd.append(dep) + break + requiredby = new_rqd + # sort out duplicate packages; this happens if something has a double # versioned depend such as a kernel module requiredby = [list(vals)[0] for _, vals in @@ -263,10 +290,24 @@ class Package(models.Model): """ Returns a list of packages with conflicts against this package. """ - # TODO: fix this; right now we cheat since we can't do proper version - # number checking without using alpm or vercmp directly. - return Package.objects.filter(conflicts__name=self.pkgname, - conflicts__comparison='').distinct() + pkgs = Package.objects.filter(conflicts__name=self.pkgname) + alpm = AlpmAPI() + if not alpm.available: + return pkgs + + # If we can use ALPM, we can filter out items that don't actually + # conflict due to the version specification. + pkgs = pkgs.prefetch_related('conflicts') + new_pkgs = [] + for package in pkgs: + for conflict in package.conflicts.all(): + if conflict.name != self.pkgname: + continue + if not conflict.comparison or not conflict.version \ + or alpm.compare_versions(self.full_version, + conflict.comparison, conflict.version): + new_pkgs.append(package) + return new_pkgs @cache_function(125) def base_package(self): -- cgit v1.2.3-2-g168b From b425b192e12afd0584bbffc9ff1d997a330bcd5a Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Wed, 8 Aug 2012 22:21:05 -0500 Subject: Migrate flag request version info to new format Signed-off-by: Dan McGee --- main/models.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'main/models.py') diff --git a/main/models.py b/main/models.py index bb2320e8..95e3c42b 100644 --- a/main/models.py +++ b/main/models.py @@ -345,12 +345,16 @@ class Package(models.Model): pkgbase=self.pkgbase).exclude(id=self.id) def flag_request(self): - if not self.flag_date: + if self.flag_date is None: return None from packages.models import FlagRequest try: + # Note that we don't match on pkgrel here; this is because a pkgrel + # bump does not unflag a package so we can still show the same flag + # request from a different pkgrel. request = FlagRequest.objects.filter(pkgbase=self.pkgbase, - repo=self.repo).latest() + repo=self.repo, pkgver=self.pkgver, + epoch=self.epoch).latest() return request except FlagRequest.DoesNotExist: return None -- cgit v1.2.3-2-g168b From 04066d190efddaf890d8573a3fbf4fd1706cb51f Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Wed, 15 Aug 2012 20:26:23 -0500 Subject: Ensure reverse conflicts match architecture if applicable Signed-off-by: Dan McGee --- main/models.py | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'main/models.py') diff --git a/main/models.py b/main/models.py index 95e3c42b..202e7fa6 100644 --- a/main/models.py +++ b/main/models.py @@ -291,6 +291,10 @@ class Package(models.Model): Returns a list of packages with conflicts against this package. """ pkgs = Package.objects.filter(conflicts__name=self.pkgname) + if not self.arch.agnostic: + # make sure we match architectures if possible + pkgs = pkgs.filter(arch__in=self.applicable_arches()) + alpm = AlpmAPI() if not alpm.available: return pkgs -- cgit v1.2.3-2-g168b From 0ec1af27aeb2ff94128c84ad53f09045cd9ee6e3 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Mon, 20 Aug 2012 21:18:18 -0500 Subject: Mark nullable fields as blank on package model This helps when creating test packages through the Django admin. Signed-off-by: Dan McGee --- main/models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'main/models.py') diff --git a/main/models.py b/main/models.py index 202e7fa6..014464ff 100644 --- a/main/models.py +++ b/main/models.py @@ -105,10 +105,10 @@ class Package(models.Model): last_update = models.DateTimeField(db_index=True) files_last_update = models.DateTimeField(null=True, blank=True) packager_str = models.CharField(max_length=255) - packager = models.ForeignKey(User, null=True, + packager = models.ForeignKey(User, null=True, blank=True, on_delete=models.SET_NULL) pgp_signature = models.TextField(null=True, blank=True) - flag_date = models.DateTimeField(null=True) + flag_date = models.DateTimeField(null=True, blank=True) objects = PackageManager() -- cgit v1.2.3-2-g168b From 78553abc51ba0f18e1c3bec015c9a11d4760c522 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Mon, 20 Aug 2012 23:48:44 -0500 Subject: Don't blow up when pgp signature data is '' on a package We handled None/NULL correctly, but not the empty string. Fix this corner case. Signed-off-by: Dan McGee --- main/models.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'main/models.py') diff --git a/main/models.py b/main/models.py index 014464ff..42f8e89a 100644 --- a/main/models.py +++ b/main/models.py @@ -143,6 +143,8 @@ class Package(models.Model): data = b64decode(self.pgp_signature) except TypeError: return None + if not data: + return None data = BinaryData(data) packets = list(data.packets()) return packets[0] -- cgit v1.2.3-2-g168b From 0926cf30f4bacf7922c2f27e4f27f78f8182aee0 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 4 Sep 2012 08:22:38 -0500 Subject: Filter out spam flag requests on package details page No need to show these as a matching request. Signed-off-by: Dan McGee --- main/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'main/models.py') diff --git a/main/models.py b/main/models.py index 42f8e89a..9ab4b4ad 100644 --- a/main/models.py +++ b/main/models.py @@ -360,7 +360,7 @@ class Package(models.Model): # request from a different pkgrel. request = FlagRequest.objects.filter(pkgbase=self.pkgbase, repo=self.repo, pkgver=self.pkgver, - epoch=self.epoch).latest() + epoch=self.epoch, is_spam=False).latest() return request except FlagRequest.DoesNotExist: return None -- cgit v1.2.3-2-g168b From d127ebf0c9303886e326577e0a91565b654e133d Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sun, 30 Sep 2012 01:41:43 -0500 Subject: PEP8 cleanups for main/models Signed-off-by: Dan McGee --- main/models.py | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'main/models.py') diff --git a/main/models.py b/main/models.py index 9ab4b4ad..166fd9a9 100644 --- a/main/models.py +++ b/main/models.py @@ -18,6 +18,7 @@ class TodolistManager(models.Manager): def incomplete(self): return self.filter(todolistpkg__complete=False).order_by().distinct() + class PackageManager(models.Manager): def flagged(self): """Used by dev dashboard.""" @@ -32,6 +33,7 @@ class PackageManager(models.Manager): return qs return qs.filter(repo__staging=False) + class Donor(models.Model): name = models.CharField(max_length=255, unique=True) visible = models.BooleanField(default=True, @@ -46,6 +48,7 @@ class Donor(models.Model): ordering = ('name',) get_latest_by = 'when' + class Arch(models.Model): name = models.CharField(max_length=255, unique=True) agnostic = models.BooleanField(default=False, @@ -62,6 +65,7 @@ class Arch(models.Model): ordering = ['name'] verbose_name_plural = 'arches' + class Repo(models.Model): name = models.CharField(max_length=255, unique=True) testing = models.BooleanField(default=False, @@ -86,6 +90,7 @@ class Repo(models.Model): ordering = ['name'] verbose_name_plural = 'repos' + class Package(models.Model): repo = models.ForeignKey(Repo, related_name="packages", on_delete=models.PROTECT) @@ -409,6 +414,7 @@ class Package(models.Model): pkgname__in=names).exclude(id=self.id).order_by( 'arch__name', 'repo__name') + class PackageFile(models.Model): pkg = models.ForeignKey(Package) is_directory = models.BooleanField(default=False) @@ -461,6 +467,7 @@ class Todolist(models.Model): domain = Site.objects.get_current().domain return '%s://%s%s' % (proto, domain, self.get_absolute_url()) + class TodolistPkg(models.Model): list = models.ForeignKey(Todolist) pkg = models.ForeignKey(Package) @@ -470,11 +477,13 @@ class TodolistPkg(models.Model): db_table = 'todolist_pkgs' unique_together = (('list','pkg'),) + def set_todolist_fields(sender, **kwargs): todolist = kwargs['instance'] if not todolist.date_added: todolist.date_added = now() + # connect signals needed to keep cache in line with reality from main.utils import refresh_latest from django.db.models.signals import pre_save, post_save -- cgit v1.2.3-2-g168b From a9998fc09e208b625edc7f39e1d6a49acb533f4b Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sun, 30 Sep 2012 09:42:48 -0500 Subject: Remote errant print() statement Signed-off-by: Dan McGee --- main/models.py | 1 - 1 file changed, 1 deletion(-) (limited to 'main/models.py') diff --git a/main/models.py b/main/models.py index 166fd9a9..00549268 100644 --- a/main/models.py +++ b/main/models.py @@ -226,7 +226,6 @@ class Package(models.Model): else: # it must be a provision of ours at this point for provide in (p for p in provides if p.name == dep.name): - print(provide.version, dep.comparison, dep.version) if alpm.compare_versions(provide.version, dep.comparison, dep.version): new_rqd.append(dep) -- cgit v1.2.3-2-g168b From bdee24b9d1279de67dd238e3644c2efff314bd7b Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Fri, 26 Oct 2012 17:11:11 -0500 Subject: Cleanup meta model attributes Signed-off-by: Dan McGee --- main/models.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'main/models.py') diff --git a/main/models.py b/main/models.py index 00549268..5700cdf1 100644 --- a/main/models.py +++ b/main/models.py @@ -62,7 +62,7 @@ class Arch(models.Model): class Meta: db_table = 'arches' - ordering = ['name'] + ordering = ('name',) verbose_name_plural = 'arches' @@ -87,8 +87,7 @@ class Repo(models.Model): class Meta: db_table = 'repos' - ordering = ['name'] - verbose_name_plural = 'repos' + ordering = ('name',) class Package(models.Model): -- cgit v1.2.3-2-g168b From 9e9157d0a8cbf9ea076231e438fb30f58bff8e29 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Fri, 16 Nov 2012 16:37:31 -0600 Subject: Use python set comprehension syntax supported in 2.7 Signed-off-by: Dan McGee --- main/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'main/models.py') diff --git a/main/models.py b/main/models.py index 5700cdf1..cc81637c 100644 --- a/main/models.py +++ b/main/models.py @@ -197,7 +197,7 @@ class Package(models.Model): """ from packages.models import Depend provides = self.provides.all() - provide_names = set(provide.name for provide in provides) + provide_names = {provide.name for provide in provides} provide_names.add(self.pkgname) requiredby = Depend.objects.select_related('pkg', 'pkg__arch', 'pkg__repo').filter( -- cgit v1.2.3-2-g168b From eea25558c766d5f3a32879d16e579d051906cbf3 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 27 Nov 2012 08:48:01 -0600 Subject: Don't cache package properties as aggressively For package signatures, it turns out it is way cheaper to just parse the signature again rather than going though all the decorator and cache_function_key business. This speeds up the mismatched signatures report significantly once this is removed. For base_package, given that we only call it once from our package details template, it makes little sense to cache the result. Signed-off-by: Dan McGee --- main/models.py | 3 --- 1 file changed, 3 deletions(-) (limited to 'main/models.py') diff --git a/main/models.py b/main/models.py index cc81637c..603d7ccc 100644 --- a/main/models.py +++ b/main/models.py @@ -141,7 +141,6 @@ class Package(models.Model): return '%s://%s%s' % (proto, domain, self.get_absolute_url()) @property - @cache_function(15) def signature(self): try: data = b64decode(self.pgp_signature) @@ -154,7 +153,6 @@ class Package(models.Model): return packets[0] @property - @cache_function(15) def signer(self): sig = self.signature if sig and sig.key_id: @@ -318,7 +316,6 @@ class Package(models.Model): new_pkgs.append(package) return new_pkgs - @cache_function(125) def base_package(self): """ Locate the base package for this package. It may be this very package, -- cgit v1.2.3-2-g168b From 4c699119820dfd060de6a0385e549f3397053548 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 4 Dec 2012 21:59:29 -0600 Subject: get_latest_by cleanups Fix some that referenced non-existent attributes, and add the attribute to other models. Signed-off-by: Dan McGee --- main/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'main/models.py') diff --git a/main/models.py b/main/models.py index 603d7ccc..8e705c54 100644 --- a/main/models.py +++ b/main/models.py @@ -46,7 +46,7 @@ class Donor(models.Model): class Meta: db_table = 'donors' ordering = ('name',) - get_latest_by = 'when' + get_latest_by = 'created' class Arch(models.Model): -- cgit v1.2.3-2-g168b From e0e2e169ec316c5d3d687e2ca211f9298f3210ee Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Thu, 27 Dec 2012 23:25:09 -0600 Subject: Remove old todo list models Signed-off-by: Dan McGee --- main/models.py | 63 ---------------------------------------------------------- 1 file changed, 63 deletions(-) (limited to 'main/models.py') diff --git a/main/models.py b/main/models.py index 8e705c54..b3cc97e1 100644 --- a/main/models.py +++ b/main/models.py @@ -14,11 +14,6 @@ from .utils import cache_function, set_created_field from packages.alpm import AlpmAPI -class TodolistManager(models.Manager): - def incomplete(self): - return self.filter(todolistpkg__complete=False).order_by().distinct() - - class PackageManager(models.Manager): def flagged(self): """Used by dev dashboard.""" @@ -423,70 +418,12 @@ class PackageFile(models.Model): db_table = 'package_files' -class Todolist(models.Model): - creator = models.ForeignKey(User, on_delete=models.PROTECT) - name = models.CharField(max_length=255) - description = models.TextField() - date_added = models.DateTimeField(db_index=True) - objects = TodolistManager() - - def __unicode__(self): - return self.name - - _packages = None - - @property - def packages(self): - if not self._packages: - # select_related() does not use LEFT OUTER JOIN for nullable - # ForeignKey fields. That is why we need to explicitly list the - # ones we want. - self._packages = TodolistPkg.objects.select_related( - 'pkg__repo', 'pkg__arch').filter(list=self).order_by('pkg') - return self._packages - - @property - def package_names(self): - # depends on packages property returning a queryset - return self.packages.values_list( - 'pkg__pkgname', flat=True).order_by().distinct() - - class Meta: - db_table = 'todolists' - - def get_absolute_url(self): - return '/todo/%i/' % self.id - - def get_full_url(self, proto='https'): - '''get a URL suitable for things like email including the domain''' - domain = Site.objects.get_current().domain - return '%s://%s%s' % (proto, domain, self.get_absolute_url()) - - -class TodolistPkg(models.Model): - list = models.ForeignKey(Todolist) - pkg = models.ForeignKey(Package) - complete = models.BooleanField(default=False) - - class Meta: - db_table = 'todolist_pkgs' - unique_together = (('list','pkg'),) - - -def set_todolist_fields(sender, **kwargs): - todolist = kwargs['instance'] - if not todolist.date_added: - todolist.date_added = now() - - # connect signals needed to keep cache in line with reality from main.utils import refresh_latest from django.db.models.signals import pre_save, post_save post_save.connect(refresh_latest, sender=Package, dispatch_uid="main.models") -pre_save.connect(set_todolist_fields, sender=Todolist, - dispatch_uid="main.models") pre_save.connect(set_created_field, sender=Donor, dispatch_uid="main.models") -- cgit v1.2.3-2-g168b From 20b64e42672d185821cc584dfa4b133ee259a144 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Fri, 28 Dec 2012 14:41:18 -0600 Subject: Reduce query count when retrieving satisfiers and providers Django doesn't attach the parent object to the child objects, even when queried through the related manager. This causes up to 3 extra queries: one to retrieve the package again, and one each for arch and repo retrieval. For a package like archboot, this drops the number of necessary queries for the package page from 805 to 222 (yes, this is still too high) and cuts the time spent waiting on the database from 505ms to 262ms. Signed-off-by: Dan McGee --- main/models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'main/models.py') diff --git a/main/models.py b/main/models.py index b3cc97e1..ba246458 100644 --- a/main/models.py +++ b/main/models.py @@ -271,10 +271,10 @@ class Package(models.Model): arches = None # TODO: we can use list comprehension and an 'in' query to make this more effective for dep in self.depends.all(): - pkg = dep.get_best_satisfier() + pkg = dep.get_best_satisfier(self) providers = None if not pkg: - providers = dep.get_providers() + providers = dep.get_providers(self) deps.append({'dep': dep, 'pkg': pkg, 'providers': providers}) # sort the list; deptype sorting makes this tricker than expected sort_order = {'D': 0, 'O': 1, 'M': 2, 'C': 3} -- cgit v1.2.3-2-g168b From abe02e3a2a6cf4fd4b0b82c2a1dd4259a9a5debe Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Fri, 28 Dec 2012 14:52:09 -0600 Subject: Retrieve arch and repo too when calling reverse_conflicts Since we need these in the template for any details links, we might as well pull them back from the database in one query rather than three. Signed-off-by: Dan McGee --- main/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'main/models.py') diff --git a/main/models.py b/main/models.py index ba246458..7ec04ad7 100644 --- a/main/models.py +++ b/main/models.py @@ -288,7 +288,7 @@ class Package(models.Model): """ Returns a list of packages with conflicts against this package. """ - pkgs = Package.objects.filter(conflicts__name=self.pkgname) + pkgs = Package.objects.normal().filter(conflicts__name=self.pkgname) if not self.arch.agnostic: # make sure we match architectures if possible pkgs = pkgs.filter(arch__in=self.applicable_arches()) -- cgit v1.2.3-2-g168b From 04f23a040a839f4989fdc83afe0f5ad4f72224be Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Mon, 31 Dec 2012 10:17:22 -0600 Subject: Add 'created' field to packages model This will be used to eventually implement the UI side of FS#13441, but to do that, we first need the data. Signed-off-by: Dan McGee --- main/models.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'main/models.py') diff --git a/main/models.py b/main/models.py index 7ec04ad7..39bc555e 100644 --- a/main/models.py +++ b/main/models.py @@ -103,6 +103,7 @@ class Package(models.Model): build_date = models.DateTimeField(null=True) last_update = models.DateTimeField(db_index=True) files_last_update = models.DateTimeField(null=True, blank=True) + created = models.DateTimeField() packager_str = models.CharField(max_length=255) packager = models.ForeignKey(User, null=True, blank=True, on_delete=models.SET_NULL) @@ -424,6 +425,8 @@ from django.db.models.signals import pre_save, post_save post_save.connect(refresh_latest, sender=Package, dispatch_uid="main.models") +# note: reporead sets the 'created' field on Package objects, so no signal +# listener is set up here to do so pre_save.connect(set_created_field, sender=Donor, dispatch_uid="main.models") -- cgit v1.2.3-2-g168b From c37fe107282f1aa4925d6c3eef9b7c1598ab4aa1 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Mon, 31 Dec 2012 10:24:09 -0600 Subject: Minor coding style tweaks Signed-off-by: Dan McGee --- main/models.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'main/models.py') diff --git a/main/models.py b/main/models.py index 39bc555e..7155d360 100644 --- a/main/models.py +++ b/main/models.py @@ -270,7 +270,8 @@ class Package(models.Model): """ deps = [] arches = None - # TODO: we can use list comprehension and an 'in' query to make this more effective + # TODO: we can use list comprehension and an 'in' query to make this + # more effective for dep in self.depends.all(): pkg = dep.get_best_satisfier(self) providers = None @@ -279,6 +280,7 @@ class Package(models.Model): deps.append({'dep': dep, 'pkg': pkg, 'providers': providers}) # sort the list; deptype sorting makes this tricker than expected sort_order = {'D': 0, 'O': 1, 'M': 2, 'C': 3} + def sort_key(val): dep = val['dep'] return (sort_order.get(dep.deptype, 1000), dep.name) -- cgit v1.2.3-2-g168b From 1b1b516bd823d807ea81e62fe14fc92c18d0b89d Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sun, 20 Jan 2013 14:59:30 -0600 Subject: Query performance enhancements in get_requiredby() For packages with particularly long lists of provides (e.g. perl), the query was getting a bit out of control with the list of names passed in. However, changing it to simply do a subquery resulted in some really poor planning by PostgreSQL. Doing this as a custom 'WHERE' clause utilizing the 'UNION ALL' SQL operator works very well. Signed-off-by: Dan McGee --- main/models.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'main/models.py') diff --git a/main/models.py b/main/models.py index 7155d360..88f0ecd1 100644 --- a/main/models.py +++ b/main/models.py @@ -190,12 +190,13 @@ class Package(models.Model): category as this package if that check makes sense. """ from packages.models import Depend - provides = self.provides.all() - provide_names = {provide.name for provide in provides} - provide_names.add(self.pkgname) + name_clause = '''packages_depend.name IN ( + SELECT %s UNION ALL + SELECT z.name FROM packages_provision z WHERE z.pkg_id = %s + )''' requiredby = Depend.objects.select_related('pkg', - 'pkg__arch', 'pkg__repo').filter( - name__in=provide_names).order_by( + 'pkg__arch', 'pkg__repo').extra( + where=[name_clause], params=[self.pkgname, self.id]).order_by( 'pkg__pkgname', 'pkg__arch__name', 'pkg__repo__name') if not self.arch.agnostic: # make sure we match architectures if possible -- cgit v1.2.3-2-g168b From 53484c45ea82a5afa8bf167f978f657b866d4c93 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sun, 20 Jan 2013 15:27:16 -0600 Subject: Fix error in get_requiredby() when checking provides The query refactor in commit 1b1b516bd removed a queryset I didn't realize was getting used elsewhere in the function. Signed-off-by: Dan McGee --- main/models.py | 1 + 1 file changed, 1 insertion(+) (limited to 'main/models.py') diff --git a/main/models.py b/main/models.py index 88f0ecd1..40466d65 100644 --- a/main/models.py +++ b/main/models.py @@ -207,6 +207,7 @@ class Package(models.Model): # version comparison operators they may specify alpm = AlpmAPI() if alpm.available: + provides = self.provides.all() new_rqd = [] for dep in requiredby: if not dep.comparison or not dep.version: -- cgit v1.2.3-2-g168b From 508d06af810c787b2644331444279407ccfa27af Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sun, 3 Feb 2013 15:08:21 -0600 Subject: Use DeveloperKey model on package page and reports This introduces the new model to the package page so subkey signings show up as attributed to the original developer. We also teach the mismatched signatures report to recognize all keys and subkeys of a given developer, cutting down on some of the bogus results. Signed-off-by: Dan McGee --- main/models.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'main/models.py') diff --git a/main/models.py b/main/models.py index 40466d65..53a24ffc 100644 --- a/main/models.py +++ b/main/models.py @@ -11,6 +11,7 @@ from django.utils.timezone import now from .fields import PositiveBigIntegerField from .utils import cache_function, set_created_field +from devel.models import DeveloperKey from packages.alpm import AlpmAPI @@ -153,8 +154,9 @@ class Package(models.Model): sig = self.signature if sig and sig.key_id: try: - user = User.objects.get( - userprofile__pgp_key__endswith=sig.key_id) + matching_key = DeveloperKey.objects.select_related( + 'owner').get(key=sig.key_id, owner_id__isnull=False) + user = matching_key.owner except User.DoesNotExist: user = None return user -- cgit v1.2.3-2-g168b From cfa2798880eccda63a3ed4d3eddadeb01f5065d2 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Mon, 4 Feb 2013 17:01:58 -0600 Subject: Update exception to DeveloperKey.DoesNotExist We aren't looking up users; we are looking up developer keys. Signed-off-by: Dan McGee --- main/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'main/models.py') diff --git a/main/models.py b/main/models.py index 53a24ffc..46fd3a63 100644 --- a/main/models.py +++ b/main/models.py @@ -157,7 +157,7 @@ class Package(models.Model): matching_key = DeveloperKey.objects.select_related( 'owner').get(key=sig.key_id, owner_id__isnull=False) user = matching_key.owner - except User.DoesNotExist: + except DeveloperKey.DoesNotExist: user = None return user return None -- cgit v1.2.3-2-g168b From 271d1babbf8038e17d9dc5cfc3cd659463848400 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sun, 20 Jan 2013 12:43:33 -0600 Subject: Revert "Reduce query count when retrieving satisfiers and providers" This reverts commit 20b64e42672d185821cc584dfa4b133ee259a144. Django 1.5 fixed this issue and now parent objects are automatically attached to their children when queries go through the related manager. See "Caching of related model instances" in the release notes. Signed-off-by: Dan McGee --- main/models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'main/models.py') diff --git a/main/models.py b/main/models.py index 46fd3a63..da9d8b6e 100644 --- a/main/models.py +++ b/main/models.py @@ -277,10 +277,10 @@ class Package(models.Model): # TODO: we can use list comprehension and an 'in' query to make this # more effective for dep in self.depends.all(): - pkg = dep.get_best_satisfier(self) + pkg = dep.get_best_satisfier() providers = None if not pkg: - providers = dep.get_providers(self) + providers = dep.get_providers() deps.append({'dep': dep, 'pkg': pkg, 'providers': providers}) # sort the list; deptype sorting makes this tricker than expected sort_order = {'D': 0, 'O': 1, 'M': 2, 'C': 3} -- cgit v1.2.3-2-g168b From 8524a6057c4b99a620850494a22eb3d1f56bee68 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sun, 20 Jan 2013 14:15:53 -0600 Subject: Change caching strategy on package.applicable_arches Rather than use the Django cache for this (aka memcached), just do it on a per-object instantiation basis. This means no external services calls except the first time to the database, which should be quite a bit faster. Signed-off-by: Dan McGee --- main/models.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'main/models.py') diff --git a/main/models.py b/main/models.py index da9d8b6e..ec5c2bd6 100644 --- a/main/models.py +++ b/main/models.py @@ -177,12 +177,15 @@ class Package(models.Model): def maintainers(self, maintainers): self._maintainers = maintainers - @cache_function(1800) + _applicable_arches = None + def applicable_arches(self): '''The list of (this arch) + (available agnostic arches).''' - arches = set(Arch.objects.filter(agnostic=True)) - arches.add(self.arch) - return list(arches) + if self._applicable_arches is None: + arches = set(Arch.objects.filter(agnostic=True)) + arches.add(self.arch) + self._applicable_arches = list(arches) + return self._applicable_arches @cache_function(119) def get_requiredby(self): -- cgit v1.2.3-2-g168b From d5a644696466e443a590317ac2f892ac279665ab Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Wed, 27 Feb 2013 08:40:23 -0600 Subject: Remove caching on reverse_conflicts We started seeing this in production with memcached usage and the upgrade to Django 1.5: PicklingError: Can't pickle : attribute lookup devel.models.UserProfile_allowed_repos failed Without having time to investigate further, something changed, likely due to the whole user profile/configurable user model shenanigans done in Django 1.5. For now, simply don't cache this attribute to work around the problem. Signed-off-by: Dan McGee --- main/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'main/models.py') diff --git a/main/models.py b/main/models.py index ec5c2bd6..9410e135 100644 --- a/main/models.py +++ b/main/models.py @@ -293,7 +293,7 @@ class Package(models.Model): return (sort_order.get(dep.deptype, 1000), dep.name) return sorted(deps, key=sort_key) - @cache_function(123) + #@cache_function(123) def reverse_conflicts(self): """ Returns a list of packages with conflicts against this package. -- cgit v1.2.3-2-g168b From d98ab844a03b0579051cece998e7c18a048c21ab Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Wed, 27 Feb 2013 09:00:17 -0600 Subject: Disable more @cache_function usage Seems the Django caching layer has changed quite a bit and is doing all sorts of funky s**t at this point. Yay for errors! Signed-off-by: Dan McGee --- main/models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'main/models.py') diff --git a/main/models.py b/main/models.py index 9410e135..a561f4f6 100644 --- a/main/models.py +++ b/main/models.py @@ -187,7 +187,7 @@ class Package(models.Model): self._applicable_arches = list(arches) return self._applicable_arches - @cache_function(119) + #@cache_function(119) def get_requiredby(self): """ Returns a list of package objects. An attempt will be made to keep this @@ -265,7 +265,7 @@ class Package(models.Model): trimmed.append(dep) return trimmed - @cache_function(121) + #@cache_function(121) def get_depends(self): """ Returns a list of dicts. Each dict contains ('dep', 'pkg', and -- cgit v1.2.3-2-g168b