6

I am trying to test my own update_or_create method written in Python, but I run into a error, I Googled it and find no answer. Here is the source code:

class ListingManager(models.Manager):#manage the creating/editting/deleting of listings
    def update_or_create_listing(self, listing_attributes, scraped = False, **extra_attributes):
        from sitebot.tasks import scrape_listing_url
        
        keys = listing_attributes.keys()
        print keys
        site = Site.objects.get(id = listing_attributes['site_id'])
        
        if 'sku' in keys and 'site_id' in keys and 'url' in keys:
            #create a listing if no such listing exists
            #SiteUrl.objects.get_or_create(href )
            listing, created = self.get_or_create(sku = listing_attributes['sku'], site = site, defaults = {'url': listing_attributes['url']}) 
            dynamo_db_listing_attributes = []
            if len(keys)> 3: 
                dynamo_db_listing_attributes = listing.create_or_update_attributes(listing_attributes = listing_attributes, **extra_attributes)
                if scraped == True and listing.scraped == False: #if the listing is already scraped, update the scraped status
                    listing.scraped = scraped
                    listing.save()
            if created == True and listing.scraped == False: #if the listing is just created and not scraped yet
                scrape_listing_url.delay(listing_id = str(listing.id), sku = listing.sku, listing_url = listing.url, scraper_name = listing.site.scraper.name) # what does delay do?
            return listing, listing_attributes 
        else:
            raise KeyError

and this is the test code:

class ListingManagerClassTests(TestCase):
    def setUp(self):
        #Generate Site for listing
        site = models.Site()
    #Generating Site requires ForeignKey Country
        country_for_site = models.Country() 
        country_for_site.save()
    #Generating Site requires ForeignKey Scraper
        scraper_for_site = models.Scraper() 
        scraper_for_site.scrapes_per_day = 1
        scraper_for_site.max_results = 10
        scraper_for_site.save()
        site.country = country_for_site
        site.scraper = scraper_for_site
        site.name = "siteforListingMangerTest"
        site.save()

    def test_create_listing(self):
        """update_or_create_listing should return the created listing"""
        lm = models.ListingManager()
        site = models.Site.objects.get(name="siteforListingMangerTest")
        listing_attributes = {'sku':'123456','site_id':site.id,
                              'url':'www.aaa.com'}
        #Create the new listing
        created_listing, created_listing_attributes = lm.update_or_create_listing(listing_attributes,False)
        #check if the retreived listing is the right one
        assertEqual(created_listing.sku, '123456')
        assertEqual(created_listing.site, site)
        assertEqual(created_listing.url,'www.aaa.com')

and the error is:

ERROR: test_create_listing (sitebot.tests.ListingManagerClassTests)
update_or_create_listing should return the created listing
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/wx2228/Desktop/BestBot/bestbot/sitebot/tests.py", line 35, in test_create_listing
    created_listing, created_listing_attributes = lm.update_or_create_listing(listing_attributes,False)
  File "/home/wx2228/Desktop/BestBot/bestbot/sitebot/models.py", line 90, in update_or_create_listing
    listing, created = self.get_or_create(sku = listing_attributes['sku'], site = site, defaults = {'url': listing_attributes['url']})
  File "/usr/local/lib/python2.7/dist-packages/django/db/models/manager.py", line 127, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/django/db/models/query.py", line 402, in get_or_create
    lookup, params = self._extract_model_params(defaults, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/django/db/models/query.py", line 457, in _extract_model_params
    for f in self.model._meta.fields:
AttributeError: 'NoneType' object has no attribute '_meta'

source code for Listing:

class Listing(models.Model):#representing the listing of an product
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    dynamoDB_connection = DynamoDBConnection(region=RegionInfo(name='us-west-2', endpoint='dynamodb.us-west-2.amazonaws.com'))
    listings_dynamo_table = Table(table_name = 'sitebot_listings', connection= dynamoDB_connection)
    sku = models.CharField(max_length=50)
    site = models.ForeignKey(Site)
    url = models.CharField(max_length=200, null = True)
    scraped = models.BooleanField(default = False)
    created = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)
    
    objects = ListingManager()
2
  • Has you an Listing model? If yes, can you provide the source? Commented Sep 24, 2015 at 23:27
  • Have you tried calling Listing.objects.update_or_create_listings ? Commented Sep 24, 2015 at 23:44

3 Answers 3

8

Instantiating the ListingManager directly prevents the query engine to find the underlying object.

You can fix this by replacing the line:

lm = models.ListingManager()

With the line:

lm = Listing.objects

(or maybe)

lm = Listing.objects.all()

Anyway, you need to refer to the Manager through the Model itself, otherwise the query manager will get lost.

It should work (I just spent half a day on a similar problem. Gotta love Django magic error messages ;) )

Sign up to request clarification or add additional context in comments.

2 Comments

lm = Listing.objects thanks! that worked for me when I was trying to mock some parts of prefetch_related query
This makes sense to me because when you call ListingManager() from the django shell you would get a new instance of an object of that model. Very different from fetching objects that already belong to a model.
3

Python is trying to find the field _meta in self.model. When it says that NoneType does not have that attribute, it means that self.model is None at the point you hit that line. You will have to trace back through your code and see why its value would be None at that point.

Comments

0

This happened to me when I rename a table and set a Foreign key of another table to it.

Make it on 2 migrations, and it should work ;)

1 Comment

This should be a comment

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.