How to use a foreign key in Django? - django

I have a video model in django. Currently when a video is saved, the current logged user is not saved in the model (Other fields have a value, except the user field). The form uses a generic create django view.
I would like to know how to save the current logged user when a new video is saved?
multimedia/models.py
from django.db import models
from django.contrib.auth.models import User
from django.forms import ModelForm
from django.core.exceptions import PermissionDenied
from django.db.models.signals import post_save
from django.contrib.auth.decorators import login_required
class Video(models.Model):
user = models.ForeignKey(User, related_name='+',blank=True, null=True)
title = models.CharField(max_length=200)
description = models.TextField()
created = models.DateTimeField('date created', auto_now_add=True, blank=False)
file_url = models.CharField(max_length=2000, blank=True)
file_name = models.CharField(max_length=255, blank=True)
file_uploaded = models.DateTimeField('date file uploaded', null=True, blank=True)
file_upload_speed = models.FloatField(null=True, blank=True)
file_size = models.IntegerField(null=True, blank=True)
def has_file(self):
return len(self.file_url) > 0
def __unicode__(self):
return self.title
#models.permalink
def get_absolute_url(self):
return ('multimedia_video_detail', [self.id])
class VideoForm(ModelForm):
class Meta:
model = Video
# fields = ('title', 'description')
exclude = ('file_url', 'file_name', 'file_uploaded','file_upload_speed', 'file_size')
multimedia/views.py
from django.conf.urls.defaults import patterns, include, url
from models import Video, VideoForm
# Uncomment the next two lines to enable the admin:
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
url(r'^$','django.views.generic.list_detail.object_list',{ 'queryset': Video.objects.all() }, name='multimedia_video_list'),
url(r'^new$', 'django.views.generic.create_update.create_object',{ 'model': Video },name='multimedia_video_new'),
url(r'^(?P<object_id>[\d]*)$', 'django.views.generic.list_detail.object_detail',{ 'queryset': Video.objects.all() }, name='multimedia_video_detail'),
url(r'^(?P<object_id>[\d]*)/edit$','django.views.generic.create_update.update_object',{ 'form_class': VideoForm }, name='multimedia_video_edit'),
url(r'(?P<object_id>[\d]*)/delete$', 'django.views.generic.create_update.delete_object', { 'model': Video, 'post_delete_redirect': '/videos' }, name='multimedia_video_delete'),
url(r'^(?P<object_id>[\d]*)/upload$','multimedia.views.upload_video',name='multimedia_video_upload'),
url(r'^(?P<object_id>[\d]*)/upload/done$','multimedia.views.upload_video_done',name='multimedia_video_upload_done'),
)
Thanks for any help to solve this issue

Instead of directly using the generic creation view, you need to use a wrapper around it that pulls the current user out of the request. Additionally, you create a model form that accepts the user, and overrides the save() method to set the user value on the model instance.
def VideoForm(user):
class _wrapped(forms.ModelForm):
class Meta:
model = models.Video
def save(self, *args, **kwargs):
self.instance.user = user
super(_wrapped, self).save(*args, **kwargs)
return _wrapped
#login_required
def create(request):
return django.views.generic.create_update.create_object(form_class=VideoForm(request.user), name='multimedia_video_new')

Related

Django - Class Based View trouble How Combine DetailView with ListView in same template

can anyone tell me how combine detailview with list view and show info in the same template, i'll explain you, i'm learning Django and i am trying to create a Questions and Answer web app, and i need to show the question with all its awnsers, i need in my detailview for a specific question show below all it awsers, something like stackoverflow does
#models.py
from django.db import models
from django.conf import settings
from django.contrib.auth.models import User
# Create your models here.
class Question(models.Model):
# user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="question", null=True)
name = models.CharField(max_length=100)
description = models.TextField(max_length=100)
date = models.DateTimeField(auto_now_add=True)
cant_resp = models.IntegerField(default=0)
question_type = models.CharField(max_length=50, choices=QUESTION_TYPES_CHOICES)
def __str__(self):
return self.description
class Anwser(models.Model):
# user = models.OneToOneField(settings.AUTH_USER_MODEL,on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="anwser", null=True)
question = models.ForeignKey(Question, on_delete=models.CASCADE)
text = models.TextField(max_length=400)
date= models.DateTimeField(auto_now_add=True)
#and this are my views.py
from django.shortcuts import render, redirect
from django.urls import reverse, reverse_lazy
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views import generic
from .forms import QuestionForm, AnwserForm
from .models import Question
# Create your views here.
class QuestionListView(LoginRequiredMixin, generic.ListView):
template_name = 'anwserquestions/question_list.html'
context_object_name = 'questions'
def get_queryset(self):
return Question.objects.all()
def createquestion(response):
if response.method == "POST":
print("Its POST method")
form = QuestionForm(response.POST)
# user =response.user
if form.is_valid():
name = form.cleaned_data["name"]
description=form.cleaned_data['description'],
question_type=form.cleaned_data['question_type'],
# date=form.cleaned_data['date'],
t = Question(name=name, description=description, question_type=question_type, cant_resp=0)
t.save()
response.user.question.add(t) # adds the to do list to the current logged in user
# return HttpResponseRedirect("/%i" %t.id)
return redirect('anwserquestions:question-list')
else:
form = QuestionForm()
return render(response, "anwserquestions/question_create.html", {"form":form})
class QuestionDetailView(LoginRequiredMixin, generic.DetailView):
model = Question
template_name = 'anwserquestions/question_detail.html'
context_object_name = 'question'
def get_queryset(self):
return Question.objects.all()
class QuestionDeleteView(LoginRequiredMixin, generic.DeleteView):
template_name = 'anwserquestions/question_delete.html'
context_object_name = 'question'
success_url = reverse_lazy('anwserquestions:question-delete')
# def get_queryset(self):
# return Question.objects.all()
You can get the related answers by including it in the views context, so you QuestionDetailView becomes
class QuestionDetailView(LoginRequiredMixin, generic.DetailView):
model = Question
template_name = 'anwserquestions/question_detail.html'
context_object_name = 'question'
def get_context_data(self, **kwargs):
context = super(QuestionDetailView, self).get_context_data(**kwargs)
context['answers'] = Answer.objects.filter(post=self.get_object())
return context

Create a social authentication functionality with google django

Hello I am a newbie and have a task to do,I have tried simple social authentication that is working but below is bit complicated:
Create a social authentication functionality with google and add user in a
database. After adding user in a database, customer should also be created
using django signals.
Note:- Customer is one to one related with user?
My models.py :
class Buddy(models.Model):
user_name=models.CharField(max_length=200,blank=True,null=True)
def __str__(self):
return str(self.user_name)
class Customer(models.Model):
customer_name=models.OneToOneField(Buddy,
on_delete = models.CASCADE,
blank=True,null=True)
def __str__(self):
return str(self.customer_name)
My settings.py includes the following lines:
SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = '2377[...].apps.googleusercontent.com'
SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = '[...]'
SOCIAL_AUTH_GOOGLE_OAUTH2_SCOPE = ['email']
INSTALLED_APPS = [ ... # oauth
'oauth2_provider',
'social_django',
'rest_framework_social_oauth2' ]
AUTHENTICATION_BACKENDS = ( # Google OAuth2
'social_core.backends.google.GoogleOAuth2',
# django-rest-framework-social-oauth2
'rest_framework_social_oauth2.backends.DjangoOAuth2', # Django
'django.contrib.auth.backends.ModelBackend', )
You have to use Django's post_save signal.
In your models.py have:
class Buddy(models.Model):
user_name=models.CharField(max_length=200, blank=True, null=True)
def __str__(self):
return str(self.user_name)
class Customer(models.Model):
# This translates into buddy_id when you migrate
buddy=models.OneToOneField(Buddy,on_delete = models.CASCADE,
blank=True, null=True)
customer_name = models.CharField(max_length=200, blank=True, null=True)
def __str__(self):
return str(self.customer_name)
In your views.py make sure you have
from django.shortcuts import render
from django.db.models.signals import post_save
from .models import Buddy
from .callbacks import save_customer
# You'll customize this view to read any parameters and provide user_name
def custom_view(request):
Buddy.objects.create(user_name="SomeUsername")
# Any of your other logic comes here, specify in the dict
return render(request, 'yourpage.html', {})
# This should be at the bottom of your views.py:
post_save.connect(save_customer, sender=Buddy)
Then create a new file in the same location called callbacks.py and there include:
from .models import Buddy
from django.db.models.signals import post_save
from django.dispatch import receiver
#receiver(post_save, sender=Buddy)
def save_customer(sender, instance, **kwargs):
# Customize your OneOnOne model on a meaningful way so it will be useful
customer = Customer.objects.create(customer_name=instance.user_name)
instance.customer = customer
instance.customer.save()
Read more about Django signals here.

Django Foreign Key model cant display in view JSON

When I run this, I get JSON file but the foreign key (contact numbers) are not included, I want to display one contact name/address/email with multiple contact numbers.
models.py
from django.db import models
class PhoneBook(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=100, default='address')
email = models.CharField(max_length=50, default='email')
note = models.CharField(max_length=100, default='note')
def __str__(self):
return self.name
class ContactNumber(models.Model):
number = models.ForeignKey(PhoneBook, related_name="contact_numbers")
contact_number= models.CharField(max_length=30)
def __str__(self):
return self.contact_number
views.py
from django.shortcuts import render
from .models import PhoneBook,ContactNumber
from django.http import JsonResponse
from django.views import View
class PhoneBookList(View):
def get(self,request):
phonebooklist=list(PhoneBook.objects.values())
return JsonResponse(phonebooklist,safe=False)
admin.py
from django.contrib import admin
from .models import PhoneBook,ContactNumber
class ContactNumberInline(admin.StackedInline):
model = ContactNumber
class PhoneBookAdmin(admin.ModelAdmin):
inlines =[
ContactNumberInline,
]
admin.site.register(PhoneBook)
admin.site.register(ContactNumber)
RESULT:
enter image description here
I might be able to answer with this approach.
class PhoneBook(models.Model):
....
def to_json(self):
contact_numbers = [c.contact_number
for c in self.contact_numbers.all()]
return {
'name': self.name,
'email': self.email,
'address': self.address,
'note': self.note,
'contact_numbers': contact_numbers
}
In your view.
class PhoneBookList(View):
def get(self,request):
phonebooklist = PhoneBook.objects.all()
serialized_data = [pb.to_json() for pb in phonebooklist]
return JsonResponse(serialized_data, safe=False)
A bit dirty solution though

Null value in column "user_id" violates not-null constraint in Django 1.9

I have exhausted all avenues in trying to put together a solution for this, but my current knowledge of Python and Django can only get me so far.
I'm creating a basic ticketing system and CreateView used to work until I created a Profile model and then separated the Ticket model into its own app. There were already a couple of tickets created when I refactored my code which is why I know ListView works, DeleteView works as well as DetailView. CreateView works until I hit the save button.
My views and models are below; I hope someone can please help me sort this out.
Ticket Model
from django.db import models
from django.contrib.auth.models import User
....
from qcapp.models import Profile
class Ticket(models.Model):
# Relations
user = models.ForeignKey(Profile, on_delete=models.CASCADE, related_name="tickets", verbose_name="user")
# Attributes
title = models.CharField(max_length=250, verbose_name="Title", help_text="Enter a Ticket Title")
color = models.CharField(max_length=7,
default="#ffffff",
validators=[RegexValidator("(^#[0-9a-fA-F]{3}$)|(^#[0-9a-fA-F]{6}$)")],
verbose_name="Color",
help_text="Enter the hex color code, like #ccc or #cccccc")
description = models.TextField(max_length=1000)
created_date = models.DateTimeField(default=timezone.now, verbose_name='Created Date')
created_by = models.ForeignKey(User, related_name='created_by_user')
# Attributes
# Object Manager
objects = managers.ProjectManager()
# Meta and String
class Meta:
verbose_name = "Ticket"
verbose_name_plural = "Tickets"
ordering = ("user", "title")
unique_together = ("user", "title")
def __str__(self):
return "%s - %s" % (self.user, self.title)
def get_absolute_url(self):
return reverse('ticket_detail', args=[str(self.id)])
Ticket View (CreateView Only)
# -*- coding: utf-8 -*-
...
from django.views.generic import CreateView, UpdateView, DeleteView
...
from .models import Ticket
...
class TicketCreate(CreateView):
model = Ticket
template_name = "tickets/ticket_form.html"
fields = ['title', 'description']
def form_valid(self, form):
form.instance.created_by = self.request.user
return super(TicketCreate, self).form_valid(form)
...
Profile Model(Imported Into Ticket Model)
from django.db import models
from django.conf import settings
from django.contrib.auth.models import User
from django.dispatch import receiver
from django.db.models.signals import post_save
from . import managers
class Profile(models.Model):
# Relations
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="profile", verbose_name="user")
# Attributes
interaction = models.PositiveIntegerField(default=0, verbose_name="interaction")
# Attributes
# Object Manager
objects = managers.ProfileManager()
# Custom Properties
#property
def username(self):
return self.user.username
# Methods
# Meta and String
class Meta:
verbose_name = "Profile"
verbose_name_plural = "Profiles"
ordering = ("user",)
def __str__(self):
return self.user.username
#receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_profile_for_new_user(sender, created, instance, **kwargs):
if created:
profile = Profile(user=instance)
profile.save()
It looks like you need to add the following to your TicketCreate class in the form_valid function:
form.instance.user = Profile.objects.get(user=self.request.user)
Let me know if that works!

grappelli admin show image

I have a new project on django, in which im using Grappelli and filebrowser, and I have extended the User to have a UserProfile related to it, my question is, how can I modify my code to be able to show on the UserProfile information of a user the profile picture uploaded, and also show it on the Users list?
This is my code now, I dont see any image on the admin!
Admin.py
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User
from models import UserProfile
class UserProfileInline(admin.StackedInline):
model = UserProfile
verbose_name_plural = 'User Profile'
list_display = ('city', 'tel', 'description', 'image_thumbnail',)
class MyUserAdmin(UserAdmin):
list_display = ('username','email','first_name','last_name','date_joined',
'last_login','is_staff', 'is_active',)
inlines = [ UserProfileInline ]
admin.site.unregister(User)
admin.site.register(User, MyUserAdmin)
Models.py
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.utils.translation import ugettext_lazy as _
from apps.common.utils.abstract_models import BaseModel
from apps.common.utils.model_utils import unique_slugify
from filebrowser.base import FileObject
from django.conf import settings
class UserProfile(BaseModel):
user = models.OneToOneField(User, related_name="profile")
city = models.CharField(_("City"), max_length=200)
tel = models.CharField(_("Phone Number"), max_length=50,
help_text=_("(Area Code) (Your phone number)"))
description = models.TextField(null=True, blank=True,
help_text = _("Small description about yourself."))
photo = models.ImageField(max_length=255, upload_to="profiles/",
null=True, blank=True, default="img/default_profile_image.png")
def image_thumbnail(self):
if self.photo:
return u'<img src="%s" width="80" height="80" />' % self.photo.version(ADMIN_THUMBNAIL).url
return u'<img src="/site_media/%s" width="80" height="80" />' % settings.DEFAULT_PROFILE_IMAGE
image_thumbnail.allow_tags = True
def __unicode__(self):
if self.user.first_name or self.user.last_name:
return "%s %s" % (self.user.first_name, self.user.last_name)
else:
return self.user.username
Well I got it, first I wanted to show the image chosen on the UserProfile inline section of the user model for the admin and also on the change list of the admin so heres what I
I changed the models.ImageField to sorl ImageField on the model.py of User profile like this
from sorl.thumbnail import ImageField
class UserProfile(BaseModel):
[...]
photo = ImageField(max_length=255, upload_to="profiles/",
null=True, blank=True, default="img/default_profile_image.png")
Then on the admin all I had to do was add sorl's AdminImageMixin on the UserProfileInline class, like this:
from sorl.thumbnail.admin import AdminImageMixin
class UserProfileInline(AdminImageMixin, admin.StackedInline):
model = UserProfile
verbose_name_plural = 'User Profile'
And that way you get an image on the UserProfile Inline section on the admin for that user, now for the change_list.
For the change list I had to do a small callable function inside the admin.py file on the UserAdmin class, heres what I did, using sorl's get_thumbnail:
from sorl.thumbnail import get_thumbnail
class MyUserAdmin(UserAdmin):
def image_thumbnail(self, obj):
im = get_thumbnail(obj.get_profile().photo, '80x80', quality=99)
return u"<img src='/site_media/%s' />" % im
image_thumbnail.allow_tags = True
list_display = ('image_thumbnail', 'username','email','first_name','last_name','date_joined',
'last_login','is_staff', 'is_active',)
And now I have a change list image of the user profile and also on the UserProfile Inline section.
Hope this works for everyone out there... and thanks #pastylegs for your previous answer!
list_display needs to be a callable:
https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_display
so you can do:
class UserProfileInline(admin.StackedInline):
def image_thumbnail(self, obj):
return obj.image_thumbnail()
image_thumbnail.short_description = 'Thumbnail'
model = UserProfile
verbose_name_plural = 'User Profile'
list_display = ('city', 'tel', 'description', 'image_thumbnail',)