Adding relation to object with preview or something like this - django

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.

Related

Django change multiple model entries

I have a model containing various entries tied to one user and I want to give the user a view where he can review these entries, select some of them and perform an action on the selection. something like the admin intereface has. I have tried UpdateView but that is for one entry only. ListView doesn't like that the model returns multiple entries for one identificator. Is there something else I could use?
EDIT:
Below is the model, I am talking about. A user will have multiple model entries and I just want a view that lists these multiple entries and allows the user to perform a bulk action on them, like delete ...
class UserData(models.Model):
class Meta:
app_label = "app"
user_id = models.IntegerField()
name = models.CharField(_("Name"),max_length=100)
latdeg = models.IntegerField(_('Latitude'))
latmin= models.IntegerField(_('Latitude'), validators=[validate_60])
londeg = models.IntegerField(_('Longitude'))
lonmin= models.IntegerField(_('Longitude'), validators=[validate_60])
main = models.BooleanField()
def __unicode__(self):
return user_id + "-" + self.name
I think what you are looking for is inlineformset_factory
Since you have not given any example, I suggest you look at the example of One author, multiple books as given in this SO post.

How to create a content tagging system for two models in Django?

Edited my question to make it more clear. And I am sorry if what i'm asking is obvious or easy to solve, I am just starting out.
Hello, I am developing a website which has 2 models for the content: Article and Comic. Now I want a system that allows me to tag Articles and Comics with certain keywords. These keywords can then be used to retrieve a list of objects from both the models and display them.
At first, I set up the system as follows:
class Article(models.Model):
.....
class Comic(models.Model):
.....
class Tag(models.Model):
tag = models.CharField(max_length = 25)
article = models.ForeignKey(Article)
comic = models.ForeignKey(Comic)
However, this did not work out.
Then I tried implementing 2 different tag models for the 2 different models: ArticleTag and ComicTag, in the following way:
class Article(models.Model):
.....
class ArticleTag(models.Model):
tag = models.CharField(max_length = 25)
article = models.ForeignKey(Article)
class Comic(models.Model):
.....
class ComicTag(models.Model):
tag = models.CharField(max_length = 25)
comic = models.ForeignKey(Comic)
This also did not work, as I was able to get a list of tags of an article, but I could not get a list of articles that had the same tag. And also it was using 2 different tag models so that was also not preferable.
A user suggested a ManyToManyField based on the previous information I had provided. However, how would this exactly work?
Now, what is the best way to create a content tagging system using Django? It should preferably work with just 3 models: Article, Comic and Tag, not 4 like I tried. In conclusion, I want a system that lets me get a list of objects from 2 models using one single tag. So, I would really appreciate help of any kind as I am an amateur programming (pretty obvious) and I am completely stumped by this problem.
You could use a ManyToManyField.
Basically something like the following. It's more intuitive if you change the name of ArticleTag.tag to ArticleTag.name. I've also added a related_name field to the M2M relationship so you can retrieve an article based on its tags using Article.objects.filter(tags__name="tag_name_here"). In the reverse direction, you could get all the tags for an article using ArticleTag.objects.filter(article__title="article_name_here").
class Article(models.Model):
title = models.CharField(max_length=140)
.....
class ArticleTag(models.Model):
name = models.CharField(max_length = 25)
articles = models.ManyToManyField(Article, related_name="tags")
[EDIT based on your updated question]
Based on your update, you could do this:
class Article(models.Model):
.....
class Comic(models.Model):
.....
class Tag(models.Model):
tag = models.CharField(max_length = 25)
articles = models.ManyToManyField(
Article,
related_name="tags",
blank=True,
null=True
)
comics = models.ManyToManyField(
Comic,
related_name="tags",
blank=True,
null=True
)
This way an Article/Comic can have many different tags, and any one tag can tag many different articles/comics. The blank=True, null=True means that you don't have to have an associated comic/article with a given tag, i.e., one tag could happen tag only comics but no articles.
To get a list of articles with the same tag:
Article.objects.filter(tags__name="your_tag_name")

Django many-to-many lookup from different models

I have some models that represents some companies and their structure. Also all models can generate some Notifications (Notes). User can see own Notes, and, of course, can't see others.
class Note(models.Model):
text = models.CharField(...)
class Company(models.Model):
user = models.ForeignKey(User)
note = models.ManyToManyField(Note, blank='True', null='True')
class Department(models.Model):
company = models.ForeignKey(Company)
note = models.ManyToManyField(Note, blank='True', null='True')
class Worker(models.Model):
department = models.ForeignKey(Department)
note = models.ManyToManyField(Note, blank='True', null='True')
class Document(models.Model)
company = models.ForeignKey(Company)
note = models.ManyToManyField(Note, blank='True', null='True')
The question is how I can collect all Notes for particular user to show them?
I can do:
Note.objects.filter(worker__company__user=2)
But its only for Notes that was generated by Workers. What about another? I can try hardcoded all existing models, but if do so dozen of kittens will die!
I also tried to use backward lookups but got "do not support nested lookups". May be I did something wrong.
EDIT:
As I mentioned above I know how to do this by enumerating all models (Company, Worker, etc. ). But if I will create a new model (in another App for example) that also can generate Notes, I have to change code in the View in another App, and that's not good.
You can get the Notes of a user by using the following query:
For example let us think that a user's id is 1 and we want to keep it in variable x so that we can use it in query. So the code will be like this:
>>x = 1
>>Note.objects.filter(Q(**{'%s_id' % 'worker__department__company__user' : x})|Q(**{'%s_id' % 'document__company__user' : x})|Q(**{'%s_id' % 'company__user' : x})|Q(**{'%s_id' % 'department__company__user' : x})).distinct()
Here I am running OR operation using Q and distinct() at the end of the query to remove duplicates.
EDIT:
As I mentioned above I know how to do this by enumerating all models
(Company, Worker, etc. ). But if I will create a new model (in another
App for example) that also can generate Notes, I have to change code
in the View in another App, and that's not good.
In my opinion, if you write another model, how are you suppose to get the notes from that model without adding new query? Here each class (ie. Department, Worker) are separately connected to Company and each of the classes has its own m2m relation with Note and there is no straight connection to User with Note's of other classes(except Company). Another way could be using through but for that you have change the existing model definitions.
Another Solution:
As you have mentioned in comments, you are willing to change the model structure if it makes your query easier, then you can try the following solution:
class BaseModel(models.Model):
user = models.Foreignkey(User)
note = models.ManyToManyField(Note)
reports_to = models.ForeignKey('self', null=True, default=None)
class Company(BaseModel):
class Meta:
proxy = True
class Document(BaseModel):
class Meta:
proxy = True
#And so on.....
Advantages: No need to create separate table for document/company etc.
object creation:
>>c= Company.objects.create(user_id=1)
>>c.note.add(Note.objects.create(text='Hello'))
>>d = Document.objects.create(user_id=1, related_to=c)
>>d.note.add(Note.objects.create(text='Hello World'))

How can I write to the instance on the parent class from a subclass in Django models?

Following on from this question...
I have two primary models for my blog, Article and Link, and both are subclasses of Post. Simplifying a little, they look something like this:
class Post(models.Model):
title = models.CharField(max_length=100)
body = models.TextField()
post_date = models.DateField(db_index=True, auto_now_add=True)
class Article(Post):
feature_image = models.FileField(upload_to='feature_images')
class Link(Post):
link = models.URLField(verify_exists=True)
I want to collect over both Articles and Links, so in my view, I run Post.objects.order_by('post_date') and presto, I get the whole list--but only with the fields that are on Post. If I want to use the link in a Link instance, I can't.
I have the primary key, so I should be able to do something like Link.objects.get(pk=item.pk) and be set--but I'd have to know if this was a Link or an Article.
Can I create a post_type property on the parent model and write to it with the correct model name from the children?
I solved this in a totally different way in the end, by writing a custom manager for Post:
class PostManager(models.Manager):
def __get_final(self, pk):
for k in Post.__subclasses__():
if k.objects.filter(pk=pk).exists():
return k.objects.get(pk=pk)
return None
def __subclass_queryset(self, qs):
collection = []
for item in qs:
collection.append(self.__get_final(item.pk))
return collection
def all(self):
return self.__subclass_queryset(super(PostManager, self).all())
Now Post.objects.all() (or any other QuerySet operation I add to the manager, like order_by), and I'll get back a list of all of the objects, with their full set of specific fields. (I then reset the manager on the subclasses, so they're not saddled with these extra queries for routine operations.)

How to create a unique_for_field slug in Django?

Django has a unique_for_date property you can set when adding a SlugField to your model. This causes the slug to be unique only for the Date of the field you specify:
class Example(models.Model):
title = models.CharField()
slug = models.SlugField(unique_for_date='publish')
publish = models.DateTimeField()
What would be the best way to achieve the same kind of functionality for a non-DateTime field like a ForeignKey? Ideally, I want to do something like this:
class Example(models.Model):
title = models.CharField()
slug = models.SlugField(unique_for='category')
category = models.ForeignKey(Category)
This way I could create the following urls:
/example/category-one/slug
/example/category-two/slug
/example/category-two/slug <--Rejected as duplicate
My ideas so far:
Add a unique index for the slug and categoryid to the table. This requires code outside of Django. And would the built-in admin handle this correctly when the insert/update fails?
Override the save for the model and add my own validation, throwing an error if a duplicate exists. I know this will work but it doesn't seem very DRY.
Create a new slug field inheriting from the base and add the unique_for functionality there. This seems like the best way but I looked through the core's unique_for_date code and it didn't seem very intuitive to extend it.
Any ideas, suggestions or opinions on the best way to do this?
What about unique_together?
class Example(models.Model):
title = models.CharField()
slug = models.SlugField(db_index=False)
category = models.ForeignKey(Category)
class Meta:
unique_together = (('slug','category'),)
# or also working since Django 1.0:
# unique_together = ('slug','category',)
This creates an index, but it is not outside of Django ;) Or did I miss the point?