Django Many to One Model Relation - django

When I creating my django models I stacked up at this point.
Now, I have a model like this:
class My_Files(models.Model):
file_name = models.CharField(max_length=50)
file_size = models.IntegerField()
... etc ...
And these files must have a relation with file which it can be uploaded to my server or http link to another server. How can I handle this relation?
Thank You

You need to use django-uploadify it helps you, in the manner such that, whenever a new file is uploaded a signal is fired with the file data, you can use that signal to populate your models. It is much easier than writing a custom signal for yourself. Hope it helps!

class My_Files(models.Model):
file_name = models.CharField(max_length=50)
file_size = models.FloatField()
file_url = models.URLField(blank=True)
file_locate = model.CharField(max_length=255, blank=True)
You also should write many methods in views and forms to fill any needed fields.

Related

Django project architecture advice

I have a django project and I have a Post model witch look like that:
class BasicPost(models.Model):
author = models.ForeignKey('auth.User', on_delete=models.CASCADE)
published = models.BooleanField(default=False)
created_date = models.DateTimeField(auto_now_add=True)
title = models.CharField(max_length=100, blank=False)
body = models.TextField(max_length=999)
media = models.ImageField(blank=True)
def get_absolute_url(self):
return reverse('basic_post', args=[str(self.pk)])
def __str__(self):
return self.title
Also, I use the basic User model that comes with the basic django app.
I want to save witch posts each user has read so I can send him posts he haven't read.
My question is what is the best way to do so, If I use Many to Many field, should I put it on the User model and save all the posts he read or should I do it in the other direction, put the Many to Many field in the Post model and save for each post witch user read it?
it's going to be more that 1 million + posts in the Post model and about 50,000 users and I want to do the best filters to return unread posts to the user
If I should use the first option, how do I expand the User model?
thanks!
On your first question (which way to go): I believe that ManyToMany by default creates indices in the DB for both foreign keys. Therefore, wherever you put the relation, in User or in BasicPost, you'll have the direct and reverse relationships working through an index. Django will create for you a pivot table with three columns like: (id, user_id, basic_post_id). Every access to this table will index through user_id or basic_post_id and check that there's a unique couple (user_id, basic_post_id), if any. So it's more within your application that you'll decide whether you filter from a 1 million set or from a 50k posts.
On your second question (how to overload User), it's generally recommended to subclass User from the very beginning. If that's too late and your project is too far advanced for that, you can do this in your models.py:
class BasicPost(models.Model):
# your code
readers = models.ManyToManyField(to='User', related_name="posts_already_read")
# "manually" add method to User class
def _unread_posts(user):
return BasicPost.objects.exclude(readers__in=user)
User.unread_posts = _unread_posts
Haven't run this code though! Hope this helps.
Could you have a separate ReadPost model instead of a potentially large m2m, which you could save when a user reads a post? That way you can just query the ReadPost models to get the data, instead of storing it all in the blog post.
Maybe something like this:
from django.utils import timezone
class UserReadPost(models.Model):
user = models.ForeignKey("auth.User", on_delete=models.CASCADE, related_name="read_posts")
seen_at = models.DateTimeField(default=timezone.now)
post = models.ForeignKey(BasicPost, on_delete=models.CASCADE, related_name="read_by_users")
You could add a unique_together constraint to make sure that only one UserReadPost object is created for each user and post (to make sure you don't count any twice), and use get_or_create() when creating new records.
Then finding the posts a user has read is:
posts = UserReadPost.objects.filter(user=current_user).values_list("post", flat=True)
This could also be extended relatively easily. For example, if your BasicPost objects can be edited, you could add an updated_at field to the post. Then you could compare the seen_at of the UserReadPost field to the updated_at field of the BasicPost to check if they've seen the updated version.
Downside is you'd be creating a lot of rows in the DB for this table.
If you place your posts in chronological order (by created_at, for example), your option could be to extend user model with latest_read_post_id field.
This case:
class BasicPost(models.Model):
# your code
def is_read_by(self, user):
return self.id < user.latest_read_post_id

Django + DRF Create file from json value

I'm building a part of django+drf app that will create article models from the given JSON request. Example of request:
{
"title":"title"
"author":"author"
"text":"possible huge amount of text"
...
}
Article model:
class Article(models.Model):
title = models.CharField(max_length=config.ARTICLE_TITLE_MAX_LENGTH)
views = models.IntegerField(default=0)
author = models.ForeignKey(User, related_name='articles', on_delete=models.CASCADE)
date_created = models.DateTimeField('Date created', auto_now_add=True)
published = models.BooleanField(default=False)
text = models.FileField(upload_to='content/articles_storage/', null=True)
This data is processed by article serializer
class ArticleSerializer(serializers.ModelSerializer):
# content = serializers.CharField() ???
class Meta:
model = Article
# fields = ['id','title','views','date_created','content']
fields = ['id','title','views','date_created','text']
Serializer expects text field to be a file, however, it is gonna be plain text, so when the user makes a POST request to the server, I want the server to validate the text, create a file from this text, save it to the folder content/article_storage
When the user makes a GET request, I want the server to read that file and create a JSON response like above.
My question is what is the best way to do this? I definitely don't want to use django's TextField. Also I'm wondering if I actually need FieldFile, maybe it's better to store the text in a file with the name = article id?

Django models in file sharing system

models.py :
class Document(models.Model):
docfile = models.FileField(upload_to='documents/%Y/%m/%d')
user = models.ForeignKey(User, null=False, blank= False)
I have created a model for file upload as shown above. docfile is the field that represents file to be uploaded and user field stores the name of the user that is uploading the file.I want the additional fields so that file uploaded is visible to the ones with whom it has been shared. Tell me the fields for achieving the sharing task.
You would another field which has a foreign key to Django User Model.
user = models.ForeignKey(User, null=False, blank= False)
then whenever you want to fetch documents based on the logged in user, you would use this
docs = Document.objects.filter(user=request.user)
In models.py
users = model.ManyToMany(User)
this should work, although am not so sure. But feel free to let me know if you by chance run into any problem
In views.py
docs = Document.users.filter(username=request.user.username)

Adding relation to object with preview or something like this

I have Document model:
class Document(models.Model):
user = models.ForeignKey(User)
title = models.CharField(max_length=255)
description = models.TextField()
content = models.TextField()
and DocumentRelation model:
class DocumentRelation(models.Model):
document_a = models.ForeignKey(Document,related_name='doc_a')
document_b = models.ForeignKey(Document,related_name='doc_b')
I have single_document views:
def single_document(request,id):
doc = Document.objects.get(id=id)
return render_to_response('single_file.html',{'doc':doc},context_instance=RequestContext(request))
In single_file.html I have:
Add related document
I need create views def add_relation(request,id):. What is the best way to add the relationship? I need a preview of the document that to be added as related. How to solve it?
(I ask about the overall design. How to solve it)
First, why are you not using a ManyToManyField in the document model like this :
related_documents = models.ManyToManyField('self')
Then you can use a two steps form if you do not want to use javascript (one to select, another to confirm and display the related document).
If you want, you can also use javascript and dynamically load the related document when the user select it.

Django: Remove an association to file but not actually delete file

When a user uploads a file, it can be used by other users to attach to their project.
class DashFile(models.Model):
dash_version = models.ForeignKey(DashVersion)
title = models.CharField(max_length=255)
file = models.FileField(upload_to=get_fs_upload_path, max_length=255)
display_order = models.IntegerField(default=99)
Basically, I clone the DashFile and so, all the values remain the same with the exception of the dash_version.
Now, if a user wants to delete the file from their project, the file gets deleted. However, that deletes the file for all other users too who have made an association to that file.
So, how can I make it so that when a user 'deletes' the file from their project, the file doesn't actually get deleted?
I also know that the design choice is incorrect. I should have not used a ForeignKey but a many to many field. But I am where I am now.
Thanks
Eric
It depends on Django version that you use. From 1.2.5 version FileField never deletes files from storage backend on model.delete().
If you use Django<1.2.5 you can implement custom FileStorage:
from django.core.files import storage
class NoDeleteStorage(storage.FileSystemStorage):
def delete(self, *a,**kw):
pass
nodelete_storage = NoDeleteStorage()
class DashFile(models.Model):
dash_version = models.ForeignKey(DashVersion)
title = models.CharField(max_length=255)
file = models.FileField(upload_to=get_fs_upload_path,
storage=nodelete_storage,
max_length=255)
display_order = models.IntegerField(default=99)