I am having trouble figuring out my problem regarding saving an image from an URL.
The problem is in the _fetch_image_from_url
method.
I get the error:
Exception Value: 'NoneType' object has no attribute 'save'
Exception Location: /home/andrej/github/curated/hosted/controller.py, line 64, in _fetch_image_from_url
I am not sure why this happens and cant get my head around it. Therefore I am reaching out.
For context here my code;
model:
class App(models.Model):
app_logo = models.ImageField(
upload_to='logos',
null=True,
blank=True
)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
repo = models.CharField(blank=True, null=True, editable=False, max_length=300)
owner = models.CharField(blank=True, null=True, editable=False, max_length=300)
github_url = models.URLField(default="", blank=False, max_length=300, unique=True)
[...]
The view is calling my “Controller”.
class AppCreateView(LoginRequiredMixin, CreateView):
form_class = AppModelForm
template_name = 'hosted/app_create_view.html'
def form_valid(self, form):
controller = CreateAppController(form.cleaned_data['github_url'])
app = controller.create()
return HttpResponseRedirect("/self-hosted")
The controller:
from urllib.parse import urlsplit
import requests
from django.core.files.base import ContentFile
from github import Github
from github.GithubException import RateLimitExceededException
from curated.settings.base import GITHUB_API_TOKEN
from hosted.models import App
from django.core.files import File
class CreateAppController:
def __init__(self, github_url):
self.owner = None
self.repo = None
self.github_url = github_url
self.github_stars = None
self.github_description = None
self.github_homepage_url = None
self.github_organization_avatar_url = None
self.app = None
self.app_logo = None
self.github_rate_limited = False
def create(self):
self._split_repo_url()
self._fetch_github_repo_data()
self._fetch_image_from_url()
self.create_app_instance()
return self.app
def _split_repo_url(self):
self.owner = urlsplit(str(self.github_url)).path.split('/')[1]
self.repo = urlsplit(str(self.github_url)).path.split('/')[2]
def _fetch_github_repo_data(self):
g = Github(GITHUB_API_TOKEN)
print(g.rate_limiting)
try:
app_data = g.get_repo(self.owner + "/" + self.repo)
self.github_stars = app_data.stargazers_count
self.github_description = app_data.description
self.github_homepage_url = app_data.homepage
if hasattr(app_data.organization, 'avatar_url'):
self.github_organization_avatar_url = app_data.organization.avatar_url
if hasattr(app_data.owner, 'avatar_url'):
self.github_organization_avatar_url = app_data.owner.avatar_url
except RateLimitExceededException as e:
self.github_rate_limited = True
print(f"Rate limit exceeded. Exception: {e}")
def _fetch_image_from_url(self):
response = requests.get(self.github_organization_avatar_url)
if response.status_code == 200:
content = ContentFile(response.content)
file_name = f'{self.owner}_{self.repo}.jpg'
self.app_logo.save(
file_name,
File(content),
save=False
)
def create_app_instance(self):
self.app = App(
owner=self.owner,
repo=self.repo,
github_url=self.github_url,
github_stars=self.github_stars,
github_description=self.github_description,
github_homepage_url=self.github_homepage_url,
github_organization_avatar_url=self.github_organization_avatar_url,
github_rate_limited=self.github_rate_limited,
app_logo=self.app_logo
)
self.app.save()
PS: This code might not be the django way. The controller idea is from a friend who is really experienced in Python but not with Django. But I liked to keep the logic out of the model and the view.