I have problems with circularity in my two files. Model import function to run when create object and this function import model to check if code in unique.
How use model in function and function in model without problem with circularity? I checked questions simillar to my problem but i still don't know to fix this issue.
models.py
from django.contrib.auth.models import User
from django.core.urlresolvers import reverse
from django.db import models
from .middleware.current_user import get_current_user
from shortener.utils import create_shortcode
from django.conf import settings
CODE_MAX_LENGTH = getattr(settings, 'CODE_MAX_LENGTH', 16)
class Shortener(models.Model):
url = models.URLField()
code = models.CharField(unique=True, blank=True, max_length=CODE_MAX_LENGTH)
author = models.ForeignKey(User, blank=True, null=True) # Allow anonymous
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
active = models.BooleanField(default=True)
def save(self, *args, **kwargs):
if not self.pk:
self.author = get_current_user()
if self.code in [None, ""]:
self.code = create_shortcode()
elif self.code.find(' ') != -1:
self.code = self.code.replace(' ', '_')
if self.url not in ["http", "https"]:
self.url = "http://{0}".format(self.url)
super(Shortener, self).save(*args, **kwargs)
def __str__(self):
return self.url
def __unicode__(self):
return self.url
def get_short_url(self):
return reverse("redirect", kwargs={'code': self.code})
Utils.py
import random
import string
from django.conf import settings
from shortener.models import Shortener
SIZE = getattr(settings, 'CODE_GENERATOR_MAX_SIZE', 12)
def code_generator(size=SIZE):
return ''.join(random.choice(string.ascii_lowercase + string.ascii_uppercase + string.digits) for _ in range(size))
def create_shortcode():
code = code_generator()
if Shortener.objects.filter(code=code).exists():
create_shortcode()
return code
Traceback:
Unhandled exception in thread started by <function check_errors.<locals>.wrapper at 0x037EAB28>
Traceback (most recent call last):
File "C:\Users\loc\shortener\lib\site-packages\django\utils\autoreload.py", line 226, in wrapper
fn(*args, **kwargs)
File "C:\Users\loc\shortener\lib\site-packages\django\core\management\commands\runserver.py", line 113, in inner_run
autoreload.raise_last_exception()
File "C:\Users\loc\shortener\lib\site-packages\django\utils\autoreload.py", line 249, in raise_last_exception
six.reraise(*_exception)
File "C:\Users\loc\shortener\lib\site-packages\django\utils\six.py", line 685, in reraise
raise value.with_traceback(tb)
File "C:\Users\loc\shortener\lib\site-packages\django\utils\autoreload.py", line 226, in wrapper
fn(*args, **kwargs)
File "C:\Users\loc\shortener\lib\site-packages\django\__init__.py", line 27, in setup
apps.populate(settings.INSTALLED_APPS)
File "C:\Users\loc\shortener\lib\site-packages\django\apps\registry.py", line 108, in populate
app_config.import_models(all_models)
File "C:\Users\loc\shortener\lib\site-packages\django\apps\config.py", line 199, in import_models
self.models_module = import_module(models_module_name)
File "E:\Python\Python35-32\lib\importlib\__init__.py", line 126, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 986, in _gcd_import
File "<frozen importlib._bootstrap>", line 969, in _find_and_load
File "<frozen importlib._bootstrap>", line 958, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 673, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 665, in exec_module
File "<frozen importlib._bootstrap>", line 222, in _call_with_frames_removed
File "C:\Users\loc\PycharmProjects\DjangoURLShortener\shortener\models.py", line 4, in <module>
from shortener.utils import create_shortcode
File "C:\Users\loc\PycharmProjects\DjangoURLShortener\shortener\utils.py", line 4, in <module>
from shortener.models import Shortener
ImportError: cannot import name 'Shortener'
Short answer: Move the create_shortcode
implementation into the models.py
module, it's just 3 lines of code to generate codes in there and you avoid the circular imports. Do the filters inside the model and Shortener.save
method with self.objects.filter(...)
.
Longer answer: The uuid
module and the uuid.uuid4
function is better (than writing a possibly buggy implementation yourself) for generating unique codes. You are, at the moment, generating 12-character or 12-byte random codes, and the UUID module can generate 16-byte codes for you out of the box. If you want enable user-definable or overridable codes but wish to generate very unique codes automatically:
code = models.CharField(unique=True, max_length=16, default=uuid.uuid4)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.