DRF: Upload many similar files - django

I have created a user API for uploading documents. The link to the file is stored in license_* type fields, the document status is stored in license_*_status.
models.py
#deconstructible
class User_directory_path(object):
def __init__(self, prefix):
self.prefix = prefix
def __call__(self, instance, filename):
return f'{instance.id}/{self.prefix}_{filename}'
class Profile(models.Model):
class DocumentStatus(models.TextChoices):
NOT_UPLOADED = 'NOT_UPLOADED'
ON_REVIEW = 'ON_REVIEW'
ACCEPTED = 'ACCEPTED'
id = models.CharField(primary_key=True, max_length=36, default=uuid.uuid4)
license_0 = models.FileField(verbose_name='License(1)',
storage=MinioBackend(bucket_name='django-backend-profiles-private', replace_existing=True),
upload_to=User_directory_path('license_0'), max_length=255, null=True, blank=True)
license_0_status = models.CharField(verbose_name='License(1) Status',
max_length=15, choices=DocumentStatus.choices, default=DocumentStatus.NOT_UPLOADED)
license_1 = models.FileField(verbose_name='License(2)',
storage=MinioBackend(bucket_name='django-backend-profiles-private', replace_existing=True),
upload_to=User_directory_path('license_1'), max_length=255, null=True, blank=True)
license_1_status = models.CharField(verbose_name='License(2) Status',
max_length=15, choices=DocumentStatus.choices, default=DocumentStatus.NOT_UPLOADED)
license_2 = models.FileField(verbose_name='License(3)',
storage=MinioBackend(bucket_name='django-backend-profiles-private', replace_existing=True),
upload_to=User_directory_path('license_2'), max_length=255, null=True, blank=True)
license_2_status = models.CharField(verbose_name='License(3) Status',
max_length=15, choices=DocumentStatus.choices, default=DocumentStatus.NOT_UPLOADED)
license_3 = models.FileField(verbose_name='License(4)',
storage=MinioBackend(bucket_name='django-backend-profiles-private', replace_existing=True),
upload_to=User_directory_path('license_3'), max_length=255, null=True, blank=True)
license_3_status = models.CharField(verbose_name='License(4) Status',
max_length=15, choices=DocumentStatus.choices, default=DocumentStatus.NOT_UPLOADED)
license_4 = models.FileField(verbose_name='License(5)',
storage=MinioBackend(bucket_name='django-backend-profiles-private', replace_existing=True),
upload_to=User_directory_path('license_4'), max_length=255, null=True, blank=True)
license_4_status = models.CharField(verbose_name='License(5) Status',
max_length=15, choices=DocumentStatus.choices, default=DocumentStatus.NOT_UPLOADED)
In this example, the user can submit 5 licenses. The field names are similar, only the postfix changes. Should I use this approach when uploading a large number of similar files?

To be honest, you have used wrong relationship between licence and Profile.
you should create a model called Licence and make a ManyToManyField
on Licence Model.
Here is an example to clarify the subject.

Related

I receive an error while migrating my models to a database

I get such an error while migrating to a database:
return Database.Cursor.execute(self, query)
django.db.utils.OperationalError: foreign key mismatch - "user_auth_customer"
referencing "user_auth_profile"
I have checked Foreign_Keys of my models and they look good.
I have no idea why I receive that error :(
Please, help me out here.
class Customer(AbstractUser):
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
objects = UserManager()
id = models.UUIDField(default=uuid.uuid4, unique=True, primary_key=True, editable=False)
profile = models.OneToOneField("Profile", related_name="user_profile",
on_delete=models.CASCADE, null=True)
first_name = models.CharField(max_length=50, null=True, blank=True)
last_name = models.CharField(max_length=50, null=True, blank=True)
username = models.CharField(max_length=30, null=True, blank=True)
phone = models.CharField(max_length=10, default='', null=True, blank=True)
email = models.EmailField(validators=[validators.EmailValidator()],
unique=True)
password = models.CharField(max_length=100, null=True, blank=True)
date_created = models.DateTimeField(auto_now_add=True)
#staticmethod
def get_customer_by_email(email):
try:
return Customer.objects.get(email=email)
except:
return False
def isExists(self):
if Customer.objects.filter(email=self.email):
return True
return False
class Meta:
verbose_name = 'Customer'
verbose_name_plural = 'Customers'
class Profile(models.Model):
first_name = models.CharField(max_length=50, null=True, blank=True)
last_name = models.CharField(max_length=50, null=True, blank=True)
phone = models.CharField(max_length=10, default='', null=True, blank=True)
email = models.EmailField(primary_key=True, unique=True, validators=[validators.EmailValidator()])
password = models.CharField(max_length=100, null=True, blank=True)
# Add a photo field
owner = models.OneToOneField(Customer, related_name='profile_owner',
on_delete=models.SET_NULL, null=True)
username = models.CharField(max_length=30, null=True, blank=True,
validators=[UnicodeUsernameValidator()])
date_created = models.DateTimeField(auto_now_add=True)
class Meta:
verbose_name = 'Profile'
verbose_name_plural = 'Profiles'
if you need any else details, I can provide you with those in the comments.
You can't have both ways OneToOneField. Choose one way.
If you delete Customer's profile field, then still you will have possibility to call relation with:
customer = Customer.objects.get(id=1)
customer.profile # that will call Customer's related Profile object
Assuming, that you will change related_name='profile_owner' to simpler related_name='profile'.
Read more about OneToOneRelationships.

DRF error create() got multiple values for keyword argument 'hnid'

so I am building a pet blog project where my scenario is - my users will be able to post multiple images and audios if they want while doing so , am facing several problems -
while trying to post through POSTMAN . I am getting an error saying create() got multiple values for keyword argument 'hnid' ..
while querying using UUID , it is throwing , a String naming "HNUsers object (e3ec1a43-ebc4-47b9-bf2f-55967af8ea71)" where I just wanted UUID(e3ec1a43-ebc4-47b9-bf2f-55967af8ea71) but came with extra HNUsers object
Here is my Profile model
class HNUsers(models.Model):
USERTYPE = (
(u'RU', u'REGULAR USER'),
(u'HN', u'HN'),
)
GENDER = (
(u'M', u'Male'),
(u'F', u'Female'),
(u'O', u'Other'),
)
ip_address = models.CharField("IP Address" , max_length=100, blank=True, null=True)
full_name = models.CharField("Full Name", max_length=100, null=True, blank=True)
username = models.CharField("Username", max_length=100, null=True, blank=True)
email = models.EmailField("Email", blank=True, null=True)
user_type = models.CharField("User Type", max_length=2, choices=USERTYPE, null=True, blank=True, default=USERTYPE[0][0])
mobile_number = models.CharField("Mobile Number", max_length=20, blank=True, null=True)
date_of_birth = models.DateField("Date of Birth", auto_now_add=False, blank=False, null=True)
gender = models.CharField("Gender", max_length=1, choices=GENDER, blank=True, null=True, )
registration_date = models.DateTimeField("Registration Date", auto_now_add=True, null=True, blank=True)
city = models.CharField("City", max_length=50, blank=True, null=True)
country = models.CharField("Country", max_length=50, blank=True, null=True)
profile_img = models.ImageField("Profile Image", blank=True, null=True)
first_img = models.FileField("First Image", blank=True, null=True)
first_img_url = models.CharField("First Image Url", blank=True, null=True, max_length=500)
profile_img_url = models.CharField("Profile Image Url", blank=True, null=True, max_length=500)
hnid = models.UUIDField("HNID", default=uuid.uuid4, unique=True, primary_key=True, editable=False)
my imagepost model
class ImagePost(models.Model):
hnid = models.ForeignKey("profiles.HNUsers", on_delete=models.DO_NOTHING)
file = models.FileField("Image", blank=True, null=True)
timestamp = models.DateTimeField("Timestamp", blank=True, null=True, auto_now_add=True)
text = models.TextField("Description text", blank=True)
class Meta:
verbose_name_plural = "Image Posts"
serializer for image post
class MultiMediaSerializer(serializers.ModelSerializer):
file = serializers.ListField(child=serializers.FileField(max_length=100, allow_empty_file=False, use_url=True))
def create(self, validated_data):
request = self.context.get('request')
# print(validated_data)
files = validated_data.pop('file')
print(files)
user = HNUsers.objects.get(pk=request.data['hnid'])
print("hnid ", user)
# print("hnid ", entry)
for img in files:
print(img)
photo = ImagePost.objects.create(file=img, hnid=user, **validated_data)
return photo
class Meta:
model = ImagePost
fields = ('hnid', 'file',)
Views.py file for the above is -
#api_view(['POST'])
#permission_classes((permissions.AllowAny,))
#parser_classes([MultiPartParser, FormParser])
def posting_api(request):
if request.method == 'POST':
data = request.data
print(data)
serializer = MultiMediaSerializer(data=data, context={'request': request})
if serializer.is_valid():
serializer.save()
print("image object saved")
return Response(serializer.data, status=status.HTTP_201_CREATED)
Sorry I am new to this
Remove hnid=user from the create statement since the validated_data does have the hnid field already
photo = ImagePost.objects.create(file=img, **validated_data)

under same username I can not post?

I am using Django 2.07. In my application after posting the first post, the second post it is not taking a post under the same username (I'm using Django all-auth). At Django admin, it shows me "this username already exits."
this is my profile model:
class Profile(models.Model):
PUBLIC = 'Public'
PRIVATE = 'Private'
INITIATIVE ='Initiative'
PRIVATE_STARTUP = 'Private and Startup'
INITIAL_KEYWORD = (
(PUBLIC, 'Public'),
(PRIVATE, 'Private'),
(INITIATIVE, 'Initiative'),
(PRIVATE_STARTUP, 'Private and Startup'),
)
Type_of_account = models. NullBooleanField('Personal account',
help_text="by default this is Business account")
user_photo = models.ImageField(upload_to='user_image', blank=True)
user = models.OneToOneField(User, on_delete=models.CASCADE, default=1)
occupation = models.CharField(max_length=400, null=False)
name = models.CharField(max_length=200, null=False, blank=False, default=None)
title = models.CharField(max_length=100, null=True, blank=True)
url = models.URLField(max_length=200, null=True, blank=True)
additional_url = models.URLField(max_length=200, null=True, blank=True )
Headquarter = models.CharField(max_length=1000, null=True, blank=True)
stock_market = models.CharField(max_length=200, null=True, blank=True)
established = models.DateField(auto_now=False, auto_now_add=False, default=None)
investors = RichTextField(null=True, blank=True)
about_details = RichTextField(null=False, blank=False, default=None)
Type_of_company = models.CharField(
max_length=20,
null=True,
blank=True,
choices=INITIAL_KEYWORD,
default=PRIVATE_STARTUP)
This is my main-model.
class MainModel(models.Model):
I_THINK = 'I think'
GOOD_PART = 'Good part'
BAD_PART ='Bad part'
PROTOTYPE = 'Prototype'
FEEDBACK = 'Feedback'
INFO = 'Info'
REVIEW = 'Review'
ASK = 'Ask'
FINACIAL_MARKET = 'Financial market'
INITIAL_KEYWORD_FOR_THOUGHTS = (
(I_THINK, 'I THINK'),
(FEEDBACK, 'FEEDBACK'),
(GOOD_PART, 'GOOD PART'),
(BAD_PART, 'BAD PART'),
(PROTOTYPE, 'PROTOTYPE'),
(INFO, 'INFO'),
(REVIEW, 'REVIEW'),
(ASK, 'ASK'),
(FINACIAL_MARKET, 'FINANCIAL MARKET')
)
user = models.OneToOneField(User, on_delete=models.CASCADE, default=None)
pub_time = models.DateTimeField('Publish time', auto_now=True)
topic = models.CharField(max_length=2000, null=True, blank=True)
##
micro_thought = models.CharField(max_length=200, null=True, blank=True)
Initial_keyword_for_thoughts = models.CharField(
max_length=300,
null=True,
blank=True,
choices=INITIAL_KEYWORD_FOR_THOUGHTS,
default=I_THINK
)
What kind of changes I have to make at main-models user field?
how I can solve this problem?
Thank you for your help.
You are using OneToOne field to relate user to Post. Using OnetoOne field a user can have atmost one post. That is the issue. Change it to ForeignKey relation.
user = models.ForeignKey(User, on_delete=models.CASCADE, default=None)

Get data from two django models

My models look like this:
class UserDevice(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT, null=False)
device = models.ForeignKey(Device, on_delete=models.PROTECT, null=False)
activation_date = models.DateTimeField(default=timezone.now, null=False)
friendly_name = models.CharField(max_length=20, null=True, blank=True)
is_owner = models.BooleanField(null=False, default=False)
is_admin = models.BooleanField(null=False, default=True)
is_alerts_enabled = models.BooleanField(null=False, default=True)
timeStamp = models.DateTimeField(auto_now = True, null=False)
class UserProfile(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT, null=False)
token = models.TextField(null=False, blank=True)
first_name = models.TextField(null=True, blank=True)
last_name = models.TextField(null=True, blank=True)
timeStamp = models.DateTimeField(auto_now = True, null=False)
I need to get device, user, is_alerts_enabled, is_admin, is_owner from UserDevice and first_name, last_name, token from userProfile. This is what I have so far and it gives me what I need from userdevice but I can't figure out how to add the userprofile stuff.
nonOwners = UserDevice.objects.filter(device=device, is_owner=False)
if nonOwners is None:
return errormsg('non nonOwners found for this device')
nonOwnersArray=[]
for nonOwner in nonOwners:
nonOwner_data = model_to_dict(nonOwner,
fieldlist=(
'device.serial',
'user.email',
'is_alerts_enabled',
'is_admin',
'is_owner',
),
rename={
'device.serial': 'serial',
'user.email': 'email'})
nonOwnersArray.append(nonOwner_data)
Any help would be greatly appreciated. Thanks!
The best way to get a dictionary of values is to use values().
UserDevice.objects.filter(device=device, is_owner=False).values('device', 'user', 'is_alerts_enabled', 'is_admin', 'is_owner')
The above line will give you the relevant fields of the UserDevice model as dictionary values.
If you add a foreign key to UserDevice (here I have changed the user field):
class UserDevice(models.Model):
user = models.ForeignKey(UserProfile, on_delete=models.PROTECT, null=False)
device = models.ForeignKey(Device, on_delete=models.PROTECT, null=False)
activation_date = models.DateTimeField(default=timezone.now, null=False)
friendly_name = models.CharField(max_length=20, null=True, blank=True)
is_owner = models.BooleanField(null=False, default=False)
is_admin = models.BooleanField(null=False, default=True)
is_alerts_enabled = models.BooleanField(null=False, default=True)
timeStamp = models.DateTimeField(auto_now = True, null=False)
You may do this:
UserDevice.objects.select_related('user').filter(device=device, is_owner=False).values('device', 'user', 'is_alerts_enabled', 'is_admin', 'is_owner', 'user__first_name', 'user__last_name', 'user__token')
I have used select_related() to avoid hitting the database unnecessarily.

Django admin widget for custom-sorted relationship

I need some help at designing a model and widget for a custom-sorted M2M relationship. The typical application scenario would be books and authors. In particular, when the order of authors in a book does matter.
The current version of my Publication model is:
class Publication(models.Model):
"""
A scientific publication.
"""
class Meta:
verbose_name = _('Publication')
verbose_name_plural = _('Publications')
ordering = ['year',]
nickname = models.CharField(
max_length=16,
help_text=_(
'A mnemonic name that "idenfies" this publication.'\
' E.g., concept_drift. (lowcase letters and dashes only)'),
validators=[RegexValidator(regex=r'^[a-z]+(_[a-z]+)*$')])
title = models.CharField(
_('Title'),
max_length=1024)
year = models.CharField(
max_length=4,
choices=YEARS,
help_text=_('Year of publication'),
db_index=True)
month = models.PositiveSmallIntegerField(
choices=MONTHS,
db_index=True,
null=True,
blank=True)
authors = models.ManyToManyField(
Person,
related_name='publications',
blank=True,
null=True)
attachment = FileBrowseField(
_('Attachment'),
max_length=256,
format='File',
blank=True,
null=True)
notes = models.CharField(
_('Notes'),
max_length=512,
help_text=_('Notes, e.g., about the conference or the journal.'),
blank=True,
null=True)
bibtex = models.TextField(
verbose_name=_('BibTeX Entry'),
help_text=_('At this moment, the BibTeX is not parsed for content.'),
blank=True,
null=True)
abstract = models.TextField(
_('Abstract'),
blank=True,
null=True)
fulltext = FileBrowseField(
_('Fulltext'),
max_length=256,
format='Document',
blank=True,
null=True)
date_updated = models.DateField(
_('Last updated on'),
auto_now=True,
db_index=True)
citation_key = models.SlugField(
max_length=512,
editable=False,
db_index=True)
#models.permalink
def get_absolute_url(self):
return ('academic_publishing_publication', (), { 'object_id': self.id })
def __unicode__(self):
return u'%s %s' % (
self.title,
self.year)
and authors are of People class:
class Person(models.Model):
"""
A person in a research lab.
"""
class Meta:
verbose_name = _('Person')
verbose_name_plural = _('People')
ordering = [
'rank',
'last_name',
'first_name', ]
affiliation = models.ManyToManyField(
Organization,
blank=True,
null=True,
related_name='people')
public = models.BooleanField(
verbose_name=_('Public?'),
help_text=_('Toggle visibility on public pages.'),
default=False)
current = models.BooleanField(
help_text=_('Is he/she still in the group?'),
default=True)
rank = models.ForeignKey(
Rank,
verbose_name=_('Academic Rank'),
related_name='people',
blank=True,
null=True)
first_name = models.CharField(
_('First Name'),
max_length=64)
mid_name = models.CharField(
blank=True,
null=True,
max_length=64)
last_name = models.CharField(
_('Last Name'),
max_length=64)
e_mail = models.EmailField(
_('E-mail'),
blank=True,
null=True)
web_page = models.URLField(
_('Web page'),
blank=True,
null=True)
description = models.TextField(
_('Description'),
blank=True,
null=True)
picture = FileBrowseField(
_('Profile picture'),
max_length=200,
format='Image',
blank=True,
null=True)
#models.permalink
def get_absolute_url(self):
return ('academic_people_person_detail', (), {'object_id': self.pk})
def __unicode__(self):
return u'%s' % self.name
def _get_name(self):
return u'%s %s' % (self.first_name, self.last_name)
name = property(_get_name)
I have two possibilities for storing the order of authors for each publication:
1. Explicit: make a AuthorForPublication model
class AuthorForPublication(models.Model):
author = ForeignKey(Person)
order = SmallPositiveInteger()
publication = ForeignKey(Publication)
but then a question arise: is it feasible to make an easy to use admin widget into Publication?
2. Workaround: create an authors_order field in Publication that takes a list of pks with a widget that lets the user re-order the authors. But this sounds a bit tricky.
Other alternatives certainly exist and are suggestions are appreciated.
I'd go for the first option. The second seems like a lot of work for very little (if any) gain.
When I need to have some explicit ordering, I always use a 'weight' column in the database.