Django models.FileField(upload_to=function1, default=function2) - django

I'm trying to set the default image in a django model with a function. Te reason is that i generate the image (a qrcode) and i want to save it with a model asociated with the request.user, it is working with the upload_to= but fails with the default, it seems it doesn't get the instance.
The code is:
-- models.py --
from django.db import models
from django.contrib.auth.models import User
import django.utils.timezone as timezone
from myproject.settings import MEDIA_ROOT
import os
def function1(instance, filename):
retun os.path.join(self.uid.username, str(instance.shortname), '.jpg')
def function2(instance):
return os.path.join(MEDIA_ROOT, str(instance.username), 'tmp.jpg')
class MyModel(models.Model):
uid = models.ForeignKey(User)
shortname = models.CharField()
qr = models.FileField(upload_to=function1, default=function2)
this gives the function2() takes exactly 1 argument (0 given)
i also tried to pass uid as parameter to function2 like this:
def function2(uid):
username = uid.username
return os.path.join(MEDIA_ROOT, username, 'tmp.jpg')
class MyModel(models.Model):
uid = models.ForeignKey(User)
shortname = models.CharField()
qr = models.FileField(upload_to=function1, default=function2(uid))
but this won't work too, gives an AttributeError exception:
'ForeignKey' object has no attribute 'username'
Any ideas on how can i tell django to upload a locally generated file (generated on the django machine at MEDIA_ROOT/request.user.username/)
Thanks!!

I found a way to solve my problem from views here:
Loading Django FileField and ImageFields from the file system

You need to be using instance instead of self. Also, function2 will not be being passed an instance.

You need to use instance instead of self. self does not exist in function1 and function2 scope:
def function1(instance, filename):
return os.path.join(instance.uid.username, str(instance.shortname), '.jpg')
def function2(instance):
return os.path.join(MEDIA_ROOT, str(instance.username), 'tmp.jpg')
class MyModel(models.Model):
uid = models.ForeignKey(User)
shortname = models.CharField()
qr = models.FileField(upload_to=function1, default=function2)
You can found docs for FileField.upload_to here
You get function2() takes exactly 1 argument, (0 given) because function2 is expecting for instance param, and if you try to pass uid like this:
class MyModel(models.Model):
uid = models.ForeignKey(User)
shortname = models.CharField()
qr = models.FileField(upload_to=function1, default=function2(uid))
will raise an error because at this point uid is a models.ForeignKey instance. You could try to do this in a pre_save signal:
def function2(sender, instance, *args, **kwargs):
if not instance.qr:
instance.qr = os.path.join(MEDIA_ROOT, username, 'tmp.jpg')
pre_save.connect(function2, sender=MyModel)

Related

Duplicate UUID if we enter a new input from html?

getting error- i saved one form from html into my database
while when i tried saving the next it gave me this error-
IntegrityError at customer
(1062, "Duplicate entry 'ad138e46-edc0-11va-b065-a41g7252ecb4'' for key 'customer.PRIMARY'")
kindly explain my uuid in models.py is -
class customer(models.Model):
customerid = models.CharField(default=str(uuid.uuid4()), max_length=500, primary_key=True)
customername=models.CharField(max_length=100)
kindly help
Updated
Form.py
class createcustomerform(ModelForm):
class Meta:
model=customer
fields=[
'customername']
Updated Models.py
import uuid
from uuid import UUID
from django.contrib.auth.models import User
from django.dispatch.dispatcher import receiver
from django.utils.translation import ugettext_lazy as _
from django.db.models.signals import pre_save
class customer(UUIDMixin,models.Model):
customername=models.CharField(max_length=100)
def __str__(self):
return self.customername
class UUIDMixin(models.Model):
uuid = models.UUIDField(blank=True,db_index=True,default=None,help_text=_('Unique identifier'),max_length=255,null=True,unique=True,verbose_name=_('UUID'))
class Meta:
abstract = True
#classmethod
def check_uuid_exists(cls, _uuid):
#Determine whether UUID exists """
manager = getattr(cls, '_default_manager')
return manager.filter(uuid=_uuid).exists()
#classmethod
def get_available_uuid(cls):
#Return an Available UUID """
row_uuid = uuid.uuid4()
while cls.check_uuid_exists(uuid=row_uuid):
row_uuid = uuid.uuid4()
return row_uuid
#receiver(pre_save)
def uuid_mixin_pre_save(sender, instance, **kwargs):
if issubclass(sender, UUIDMixin):
if not instance.uuid:
manager = getattr(instance.__class__, '_default_manager')
use_uuid = uuid.uuid4()
while manager.filter(uuid=use_uuid):
use_uuid = uuid.uuid4()
instance.uuid = use_uuid
#Automatically populate the uuid field of UUIDMixin models if not already populated.
You should use a proper UUIDField and avoid setting a default value.
Make sure the value is set when the object is created, and also ensure that the value is unique - obviously the chance of duplication in a UUID is incredibly small which is the whole point.
You could create yourself a model mixin which will add a uuid to your model(s) and ensure that the value is set when the object is saved;
class UUIDMixin(models.Model):
"""
Mixin for models contain a unique UUID, gets auto-populated on save
"""
uuid = models.UUIDField(
blank=True,
db_index=True,
# default=uuid.uuid4,
# NB: default is set to None in migration to avoid duplications
default=None,
help_text=_('Unique identifier'),
max_length=255,
null=True,
unique=True,
verbose_name=_('UUID'),
)
class Meta:
"""Metadata for the UUIDMixin class"""
abstract = True
#classmethod
def check_uuid_exists(cls, _uuid):
""" Determine whether UUID exists """
manager = getattr(cls, '_default_manager')
return manager.filter(uuid=_uuid).exists()
#classmethod
def get_available_uuid(cls):
""" Return an Available UUID """
row_uuid = uuid.uuid4()
while cls.check_uuid_exists(uuid=row_uuid):
row_uuid = uuid.uuid4()
return row_uuid
#receiver(pre_save)
def uuid_mixin_pre_save(sender, instance, **kwargs):
"""
Automatically populate the uuid field of UUIDMixin models if not already
populated.
"""
if issubclass(sender, UUIDMixin):
if not instance.uuid:
manager = getattr(instance.__class__, '_default_manager')
use_uuid = uuid.uuid4()
while manager.filter(uuid=use_uuid):
use_uuid = uuid.uuid4()
instance.uuid = use_uuid
Based on your comment, let me explain more.
The above is an abstract model, meaning it doesn't create a table itself, it can just be used by other (concrete) models so that they can use what it defines.
It's a benefit of classes & inheritance. Allowing you to not duplicate code on things that will be useful on many models.
No, in the meta you'll see abstract = True. So you define your models like MyModel(UUIDMixin, models.Model) and it gets a uuid field from this abstract model along with whatever you define.
You would use it by doing something like this;
class Customer(UUIDMixin, models.Model):
name = models.CharField(max_length=100)
If you really want to use the UUID as a primary key, maybe setup two mixins, a PrimaryUUIDMixin and the UUIDMixin, because on the whole a smaller value on the primary key may be more efficient.
You also mentioned Undefined variable: _
Typically in django you'd see an import at the top of the file like this;
from django.utils.translation import ugettext_lazy as _
This is then used to wrap strings so that they can be translated, for example, _("Hello")
Even if you don't translate your project, it's common to just include this anyway. You can read up on that here; https://docs.djangoproject.com/en/3.1/topics/i18n/translation/#standard-translation

Why do I have to reference the user model this way

I was working on a Django project and I was trying to do something like this to make sure that my model worked no matter what user model is set.
from django.contrib.auth import get_user_model
class Item(models.Model):
title = models.CharField(max_length=100, )
description = models.TextField()
seller = models.ForeignKey(get_user_model())
However when I did this it resulted in errors telling me the user model couldn't be accessed so I had to change it to this
from django.conf import settings
class Item(models.Model):
title = models.CharField(max_length=100, )
description = models.TextField()
seller = models.ForeignKey(settings.AUTH_USER_MODEL)
This works fine but I thought I have done this in the past using the first method. The only difference that time being that I was using a custom user model. They both seem like they are doing the same thing to me so why do I have to use the second method? And does get_user_model() not work with the default user?
This is the source code of the get_user_model() in django:
def get_user_model():
"""
Returns the User model that is active in this project.
"""
from django.db.models import get_model
try:
app_label, model_name = settings.AUTH_USER_MODEL.split('.')
except ValueError:
raise ImproperlyConfigured("AUTH_USER_MODEL must be of the form 'app_label.model_name'")
user_model = get_model(app_label, model_name)
if user_model is None:
raise ImproperlyConfigured("AUTH_USER_MODEL refers to model '%s' that has not been installed" % settings.AUTH_USER_MODEL)
return user_model
As you can see, it pulls the AUTH_USER_MODEL variable from your settings as you do but extracting the app_label and the user class itself. If it does not work you should see one of the two errors in the terminal when this call is done.
I think your answer lies in the Django source. It depends on your setup what happens. Older versions might do it a bit differently.

DetailView using two ForeignKey kwargs

I am trying to utilize Django's class-based generic DetailView by querying the table using two keyword arguments passed via the url. I have tried overriding both the get_queryset() and get_object() method to no avail. My models look like this (edited for brevity, but let me know if something important is missing):
# models
class Skill(models.Model):
skill = models.CharField()
class User(AbstractBaseUser):
username = models.CharField()
class UserSkills(models.Model):
skill = models.ForeignKey(Skill)
user = models.ForeignKey(User, to_field='username')
value = models.CharField()
my url for the DetailView looks like this:
url(
regex=r"^(?P<username>[a-zA-Z0-9-]{1,25})/skills/(?P<skill>[a-zA-Z0-9 -._/]+)/$",
view=views.UserSkillDetail.as_view(),
name='userskill_detail',
),
the view:
class UserSkillDetail(DetailView):
template_name = 'UserSkill_detail.html'
context_object_name = 'skill'
model = UserSkills
def get_object(self, queryset=None):
get_user = self.kwargs['username']
get_skill = self.kwargs['skill']
return get_object_or_404(UserSkills, user__username=get_user, skill__skill=get_skill)
I keep receiving the following error via the template debug message:
No UserSkills matches the given query.
although I am able to successfully query the following via the shell:
>>> x = UserSkills.objects.get(user__username='user1', skill__skill='skill1')
>>> x
<UserSkills: user1#example.com: skill1>
and have verified that the keyword arguments are being captured correctly ('user1', 'skill1') via the logger and Django debug toolbar. Any help would be greatly appreciated!
There was an issue with my migration sequence (called out of intended order). I reconfigured the migrations and everything worked.

Trying to create a progress app with Django ContentType and GenericForeignKey

I have an app that I'm calling Progress. I want to have several different apps throughout my project write to it whenever something happens. But all the different apps are not the same in how they broadcast progress. So I thought that a ContentType solution would work.
The only trick that I'm having a hard time figuring out is that I need to write to the Progress app when an event occurs. Such as when a view renders. I've been trying get_or_create but I'm having trouble getting the right configuration in the queryset. Any suggestions for how to correct this?
I want the get_or_create to sit in the view of an app so that the action I want is what writes to the progress.
My Progress Model.py
from django.db import models
from django.template.defaultfilters import slugify
from django.utils.translation import ugettext_lazy as _
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
from datetime import datetime
class Progress(models.Model):
"""
The page log. Records the user and the object.
"""
user = models.ForeignKey(User, related_name='user_pagelog')
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type', 'object_id')
stamp = models.DateTimeField(auto_now_add=True)
class Meta:
unique_together = (('user', 'content_type', 'stamp'),)
verbose_name = 'View Log'
verbose_name_plural = 'View Logs'
get_latest_by = 'stamp'
def __str__(self):
return "%s got to %s on %s" % (self.user, self.content_type, self.stamp)
#classmethod
def get_latest_view(cls, user):
"""
Get most recent view log value for a given user.
"""
try:
view_log = cls.objects.filter(user=user).order_by('-stamp')[0]
return view_log.value
except IndexError:
return None
An example of the queryset that I want to write to the Progress app:
Progress.objects.get_or_create(user=request.user, content_type=f.id)
Where f = get_object_or_404(Page, publish=True)
Finally, the error I'm getting:
Cannot assign "1": "Progress.content_type" must be a "ContentType" instance.
Which I think it means the instance isn't getting found? But it exists, so I'm confused.
Thanks.
No, it doesn't mean that at all. It means what it says, that the parameter has to be an instance of the ContentType model, whereas you're passing the ID of the object itself.
You might be able to use content_type along with the actual instance:
Progress.objects.get_or_create(user=request.user, content_object=f)
Otherwise you'll need to get the right ContentType using the get_for_model() method, and pass that along with the object id.

Django social_auth custom user model FacebookBackend explanation

I'm trying to use social_auth (omab) for the first time and I'm find that there is no working example how to store basic facebook user data. Authentication works and user is created without problem as it's explained in the social_auth docs but I need to store gender and locale also. Both of them belongs to the basic facebook user data so they are in the facebook response all the time.
I'm use Django 1.4, Python2.7 and latest social_auth. So I was try to use SOCIAL_AUTH_USER_MODEL = 'myapp.UserProfile' in settings.py file and model.py is:
#!/usr/bin/python
#-*- coding: UTF-8 -*-
from django.db import models
from django.contrib.auth.models import User
from django.db.models import signals
import datetime
from datetime import timedelta
from django.db.models.signals import post_save
from social_auth.signals import pre_update
from social_auth.backends.facebook import FacebookBackend
class CustomUserManager(models.Manager):
def create_user(self, username, email):
return self.model._default_manager.create(username=username)
class UserProfile(models.Model):
gender = models.CharField(max_length=150, blank=True)
locale = models.CharField(max_length=150, blank=True)
#social_auth requirements
username = models.CharField(max_length=150)
last_login = models.DateTimeField(blank=True)
is_active = models.BooleanField()
objects = CustomUserManager()
class Meta:
verbose_name_plural = 'Profiles'
def __unicode__(self):
return self.username
def get_absolute_url(self):
return '/profiles/%s/' % self.id
def facebook_extra_values(sender, user,response, details, **kwargs):
profile = user.get_profile()
current_user = user
profile, new = UserProfile.objects.get_or_create(user=current_user)
profile.gender = response.get('gender')
profile.locale = response.get('locale')
profile.save()
return True
pre_update.connect(facebook_extra_values, sender=FacebookBackend, weak = False, dispatch_uid = 'facebook_extra_values_user')
In the settings.py I'm define pipeline
SOCIAL_AUTH_PIPELINE = (
'social_auth.backends.pipeline.social.social_auth_user',
#'social_auth.backends.pipeline.associate.associate_by_email',
'social_auth.backends.pipeline.user.create_user',
'social_auth.backends.pipeline.social.associate_user',
'social_auth.backends.pipeline.social.load_extra_data',
'social_auth.backends.pipeline.user.update_user_details',
'social_auth.backends.pipeline.misc.save_status_to_session',
)
but with above I get error AssertionError: ForeignKey(None) is invalid. First parameter to ForeignKey must be either a model, a model name, or the string 'self'
Also I was try to use AUTH_PROFILE_MODULE = 'myapp.UserProfile' instead as I was do before to extend user.model, which works well but don't understand how to populate needed data when UserProfile is created. Does anyone can place working code for this problem?
Thanks
There are a couple of ways to archive it, what fits better to your project is up to you of course, here's a list of available options:
Define this setting FACEBOOK_EXTRA_DATA = ('gender', 'locale'), the values will be available at the UserSocialAuth instance, to get them just do user.social_auth.get(provider='facebook').extra_data['gender'] or ['locale']. This is possible just because the information is available in the basic user data response.
Use a user profile to store this data (check django doc about it). Then just add a pipeline entry that stores the values in your profile instance.
Create a custom user model, SOCIAL_AUTH_USER_MODEL = 'myapp.CustomUser', and again add a custom pipeline entry that stores the values in your user instance.
Number 1 is not the best solution IMO, since a user can have several Facebook accounts connected and it could create a mess. Number 2 is good for Django 1.4 and lower, but it's deprecated starting from Django 1.5, something to take into account. Number 3 is a bit messy IMO.