How to save many to many relationship? - django

I'm almost using following code(I striped down a little bit), I use auto complete light to load users and users can insert different people name(users) seperated by comma. the problem is when I try to save I get following error
ValueError at /write/
"<Article: test1>" needs to have a value for field "article" before this many-to-many relationship can be used.
models.py
class Article(models.Model):
author = models.ForeignKey(User,)
people = models.ManyToManyField(User, related_name="with", null=True,)
content = models.TextField()
forms.py
class ArticleForm(forms.ModelForm):
people = forms.CharField(widget=autocomplete_light.TextWidget('UserAutocomplete'))
class Meta:
model = Article
views.py
def write(request):
if request.POST:
form = ArticleForm(request.POST)
if form.is_valid():
content = form.cleaned_data['content']
user = User.objects.get(username=request.user.username)
people_str = form.cleaned_data['accompanied']
people = [x.strip() for x in accompanied_str.split(',')]
article = Article(
content = content,
author = user,
)
for username in accompanied:
user = User.objects.get(username=username)
article.people.add(user)
article.save()
return HttpResponseRedirect('/success/')

In order to create a relation you need the ids of both side. The newly created article has no id yet. If you save the article first and then add people to it it should work fine.
article = Article(
content = content,
author = user,
)
article.save()
article.add(*User.objects.filter(username__in=accompanied))
The process of adding people can be cheaper by getting all users that have a username from the list of accompanied in one fetch.

Related

Matching query does not exist (Django)

I created a forum website.
When pressing on a user profile i get and error in console that library.models.SiteUser.DoesNotExist: SiteUser matching query does not exist.
And in the browser it also displays:
DoesNotExist at /profile/1/
SiteUser matching query does not exist.
Browser highlights this line
userprof = SiteUser.objects.get(id=pk)
This is my views.py:
def userProfile(request, pk):
user = User.objects.get(id=pk)
**userprof = SiteUser.objects.get(id=pk)**
posts = user.post_set.all()
post_comments = user.comment_set.all()
interests = Interest.objects.all()
context = {
'user': user,
'userprof': userprof,
'posts': posts,
'post_comments': post_comments,
'interests': interests
}
return render(request, 'library/profile.html', context)
models.py:
class SiteUser(models.Model):
page_user = models.OneToOneField(User, on_delete=models.CASCADE)
about = HTMLField()
profile_pic = models.ImageField('profile_pic', upload_to='covers', null=True)
Any help would be greatly appreciated.
If you have relations, then always use them if possible. Instead of getting SiteUser having a User pk (it does not have to be always the same), get it using the relation between them:
# bad and risky
user = User.objects.get(id=pk)
userprof = SiteUser.objects.get(id=pk)
# good and always working if object exists
user = User.objects.get(id=pk)
userprof = user.siteuser
Good practice is to name related_name argument for such usage:
class SiteUser(models.Model):
page_user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='foobar')
Then you can call it like:
user = User.objects.get(id=pk)
userprof = user.foobar
User and SiteUser primary keys will not be same. You can easily get SiteUser from the following query:
userprof = user.siteuser # efficient solution
Or
userprof = SiteUser.objects.get(page_user_id=pk) # alternative solution but should not be used in this code sample
Because of their OneToOne relation. For more information, please check the documentation.

Why won't my signal-triggered function for saving a model instance actually save?

I'm trying to get into DJango, and I'm building a simple blog website. There is a model called BlogPost:
class BlogPost(models.Model):
slug = None
title = models.CharField(max_length = 100)
content = models.TextField('Page Content')
upload_date = models.DateField(auto_now = True)
Usually, when there are blog posts, the posts have links that do not end in None, but I have my model this way because I want my website to automatically generate the slug based on the post's title using the following signal-triggered function:
#receiver(signals.post_save,sender = BlogPost)
def set_slug(sender,instance,**kwargs):
if instance.slug:
return
instance.slug = parse.quote(instance.title)
instance.save()
The if-statement should change .slug to a URL-encoded version of the post's title when I save the new instance of the model in the admin site, but when I check the value of .slug, it's always None.
Why is that?

How to show the user the posts (or movies) in this case they have liked?

I have a user profile page where I want to show the user the movies they have liked.
Here is the part of model which contains the like field as an ManyToManyField.
class moviefiles(models.Model):
name = models.CharField(max_length=50)
duration = models.CharField(max_length=20)
.
.
.
liked = models.ManyToManyField(User, related_name='movie_like')
rt = models.IntegerField(default=1)
Here is the def in view for liking or unliking:
def movieLike(request, slug):
user = request.user
if user.is_authenticated:
post = get_object_or_404(moviefiles, slug=request.POST.get('post_id'))
liked = False
if post.liked.filter(id=request.user.id).exists():
post.liked.remove(request.user)
liked = False
return HttpResponseRedirect(reverse('movie-about', args=[str(slug)]))
else:
post.liked.add(request.user)
liked = True
return HttpResponseRedirect(reverse('movie-about', args=[str(slug)]))
else:
return redirect('/user/signup')
I am using MongoDB as the database and django made two tables in it on running makemigrations, one is the home_moviefiles and another is home_moviefiles_liked which is storing the liked data and the data of liking or unliking is getting saved correctly.
I'm trying to retrieve the the movies which a user has liked but I am unable to proceed from here.

Updating model objects in the database on Django

I am new to Django and for learning purposes I am trying to build my own site using the linkedn API to display my profile. The following is a a example of my code. To see the whole lot:
https://github.com/javiee/django-site
models.py
class Profile(models.Model):
user = models.ForeignKey(User)
first_name = models.CharField(max_length=20)
last_name = models.CharField(max_length=20)
def __str__(self):
return self.first_name, self.last_name
class Education(models.Model):
user = models.ForeignKey(User)
school_name = models.CharField(max_length=100)
field_study = models.CharField(max_length=100)
degree = models.CharField(max_length=100)
start_date = models.CharField(max_length=20)
end_date = models.CharField(max_length=20)
and views.py
profile = Profile(first_name = content['firstName'],
last_name = content['lastName'],
user = request.user)
profile.save()
#Education model
content_educ = content['educations']['values']
for value in content_educ:
education = Education(school_name = value['schoolName'],
user = request.user,
field_study = value['fieldOfStudy'],
degree = value['degree'],
start_date = value['startDate']['year'] ,
end_date = value['endDate']['year'])
education.save()
This all working but my problem is that everytime I check linkedn, the code saves all the objects again. What it would ideally do is to "update" fields based on the profile when the .save() method is called. I have read the next link https://docs.djangoproject.com/en/1.7/ref/models/instances/#saving-objects
but I dont manage to get it working, perhaps foreigns keys are not properly set so any advise/help/tip will be much appreciated. Thanks!
Use the update_or_create() method:
Education.objects.update_or_create(
school_name=value['schoolName'],
user = request.user,
defaults={'field_study': value['fieldOfStudy'],
'degree': value['degree'],
'start_date': value['startDate']['year'] ,
'end_date': value['endDate']['year']})
The problem you're having is that you're instantiating new Education instances in these lines:
education = Education(school_name = value['schoolName'],
user = request.user,
field_study = value['fieldOfStudy'],
degree = value['degree'],
start_date = value['startDate']['year'] ,
end_date = value['endDate']['year'])
When Django goes and tries to save these new instances (instances for which id is not yet defined), Django goes ahead and inserts the records rather than doing the update you want.
To do an update, you can either try to get the record, catching the DoesNotExist exception:
try:
education = Education.objects.get(school_name=value['schoolName'],
user=request.user,
field_study=value['fieldOfStudy'],
degree=value['degree'],
start_date=value['startDate']['year'],
end_date=value['endDate']['year'])
except Education.DoesNotExist:
education = Education(school_name=value['schoolName'],
user=request.user,
field_study=value['fieldOfStudy'],
degree=value['degree'],
start_date=value['startDate']['year'],
end_date=value['endDate']['year'])
then apply whatever updates you want/need.
Or you can use get_or_create to do the same:
(education, created) = Education.objects.get_or_create(school_name=value['schoolName'],
user=request.user,
field_study=value['fieldOfStudy'],
degree=value['degree'],
start_date=value['startDate']['year'],
end_date=value['endDate']['year'])
If you don't want to look up your instances by all of those values (they're AND-ed), but want to initialize new instances with certain values, you should look up the defaults keyword for get_or_create.
Or you can use update_or_create as suggested by catavaran.
edit: Or, if you just want to do a straight update of a record without getting it (this also works with multiple objects at once), you can use queryset.update
Education.objects.filter(attribute=value, ...).update(attribute2=value2, ...)

How to get logged-in user info in Django's forms.py

I have created a Profile model including the Gender info. There is also models called Dorm and Registration (not used for user registration) like this:
class Registration(models.Model):
user = models.ForeignKey(User)
pref1 = models.ForeignKey(Dorm, related_name="pref1",verbose_name=u"Preference 1",null=True)
...
friend1 = models.CharField(u"Friend 1", max_length=15,blank=True)
class Dorm(models.Model):
name = models.ForeignKey(Building)
gender = models.CharField(u"Gender", max_length=1, blank=True, choices=GENDER_CHOICES)
Now, i am trying to generate a form for this Registration model with forms.ModelForm like this:
class RegistrationForm(forms.ModelForm):
dorms = Dorm.objects.filter(gender='M')
pref1 = forms.ModelChoiceField(queryset=dorms, empty_label=None)
...
class Meta:
model = Registration
exclude = ('user')
as you can see in the second line, i am querying the dorms with a hardcoded gender value M. Instead of the hardcoded value, I need to get the users' gender, and query the database with that gender information.
I have been searching the documentation but I could not find anything. Can you help me? How can I learn the logged-in User' profile information in Django Forms?
So without using some sort of monkeying around of the init function a "form_factory" is probably the best approach.
def RegFormFactory(user)
dorms = Form.objects.filter(gender = "user.gender")
class _RegistrationForm(forms.ModelForm):
pref1 = forms.ModelChoiceField(queryset = dorms, empty_label=None)
class Meta:
model = Registration
exclude = ('user')
return _RegistrationForm
then use:
formclass = RegFormFactory(user)
form_inst = formclass()
...
form_inst = formclass(request.POST)
This is described very nicely in a blog post here: So you want a dynamic form.
James Bennett wrote a blog post that should explain perfectly what you need: So you want a dynamic form