Foriegnkey issue while submitting the form - django

This post extends the error while submitting data in the form django
model.py
from django.db import models
# Create your models here.
class Profile(models.Model):
name = models.CharField(max_length=50, primary_key=True)
assign = models.CharField(max_length=50)
doj = models.DateField()
class Meta:
db_table= 'profile'
def __unicode__(self):
return u'%s' % (self.name)
class working(models.Model):
w_name =models.ForeignKey(Profile, db_column='w_name')
monday = models.IntegerField(null=True, db_column='monday', blank=True)
tuesday = models.IntegerField(null=True, db_column='tuesday', blank=True)
wednesday = models.IntegerField(null=True, db_column='wednesday', blank=True)
class Meta:
db_table = 'working'
def __unicode__(self):
return u'%s ' % ( self.w_name)
view.py
# Create your views here.
from forms import *
from django import http
from django.shortcuts import render_to_response, get_object_or_404
def index(request):
obj=working()
obj.w_name='X'
obj.Monday=1
obj.Tuesday=2
obj.Wednesday =3
obj.save()
return http.HttpResponse('Added')
Here i want to insert the data directly into table ,if person click on http://127.0.0.1:8000/
But it throws below error any thoughts ??
Exception Type: ValueError at /
Exception Value: Cannot assign "u'x'": "working.w_name" must be a "Profile" instance.

I thought you were saying you wanted to inject values into a form?
In this case, it's clear (see it's better than comments), you need to pass in a Profile instance to your working object just as we did in the form clean method in your other post.
def index(request):
try:
profile = Profile.objects.get(pk='X')
except Profile.DoesNotExist:
assert False # or whatever you wish
obj=working()
obj.w_name= profile
obj.Monday=1
obj.Tuesday=2
obj.Wednesday =3
obj.save()
return http.HttpResponse('Added')

Related

My views.py is returning null from django admin object

I would really appreciate some help on this because I'm completely stuck. I've started up a simple django app (trying to make an instagram clone). However, when I try to display the post objects (which I created in the django admin page) nothing is displayed in index.html, so I tried printing out the objects in the views.py and it's returning to me an empty query set. I don't quite understand what I'm doing wrong and why I can't access the objects? When I print out the username I am able to get that, but then nothing for both post and stream objects. Please I'm so stuck any advice would be appreciated.
views.py
from django.shortcuts import render
from django.contrib.auth.decorators import login_required
from django.template import loader
from django.http import HttpResponse
# Create your views here.
from post.models import post, stream
#login_required
# we are getting all of the string objects that are created for the user
def index(request):
user = request.user
print(user)
posts = stream.objects.filter(user=user)
print(posts)
group_ids = []
#then looping through and getting post id to a list
for posted in posts:
group_ids.append(posted.post_id)
print(group_ids)
#then filtering them so that you can display it in the index
#selecting a specific post by id
post_items = post.objects.filter(id__in=group_ids).all().order_by('-date')
template = loader.get_template('index.html')
context = {'post_items' : post_items}
return(HttpResponse(template.render(context, request)))
models.py
from django.db import models
from django.contrib.auth.models import User
import uuid
# Create your models here.
from django.db.models.signals import post_save
from django.utils.text import slugify
from django.urls import reverse
def user_directory_path(instance,filename):
# this file is going to be uploaded to the MEDIA_ROOT /user(id)/filename
return('user_{0}/{1}'.format(instance.user.id,filename))
class tag(models.Model):
title = models.CharField(max_length = 80, verbose_name = 'tag')
slug = models.SlugField(null = False, unique = True)
class Meta:
verbose_name = 'tag'
verbose_name_plural = 'tags'
# for when people click on the tags we can give them a url for that
# def get_absolute_url(self):
# return(reverse('tags', args = [self,slug]))
def __str__(self):
return(self.title)
def save(self,*args, **kwargs):
if not self.slug:
self.slug = slugify(self.title)
return(super().save(*args, **kwargs))
class post(models.Model):
# will create a long id for each post
id = models.UUIDField(primary_key=True, default = uuid.uuid4, editable = False)
image = models.ImageField(upload_to = user_directory_path, verbose_name= 'image', null = True)
caption = models.TextField(max_length = 2000, verbose_name = 'caption')
date = models.DateTimeField(auto_now_add = True)
tags = models.ManyToManyField(tag, related_name='tags')
user = models.ForeignKey(User, on_delete=models.CASCADE)
likes = models.IntegerField()
def get_absolute_url(self):
return reverse('postdetails', args=[str(self.id)])
# def __str__(self):
# return(self.user.username)
class follow(models.Model):
follower = models.ForeignKey(User, on_delete=models.CASCADE, related_name='follower')
following = models.ForeignKey(User, on_delete=models.CASCADE, related_name='following')
class stream(models.Model):
following = models.ForeignKey(User, on_delete=models.CASCADE, related_name='stream_following')
user = models.ForeignKey(User, on_delete=models.CASCADE)
post = models.ForeignKey(post, on_delete=models.CASCADE)
date = models.DateTimeField()
def add_post(sender, instance,*args, **kwargs):
# here we are filtering all the users that are following you
post = instance
user = post.user
followers = follow.objects.all().filter(following=user)
for follower in followers:
streams = stream(post=post, user=follower.follower, date = post.date, following = user)
streams.save()
post_save.connect(stream.add_post, sender=post)
output from print statements
user
<QuerySet []>
[]
I figured it out. It wasn't an issue with the code, but the way that I was creating posts in the admin panel. So because you can only view posts from users that you are following, the posts that I was creating weren't showing up. So I had to create another user, and follow that user, then have the new user post something. Then the post shows up in the page!

Django has no object attribute named text - but I don't expect it to?

I have the below structure,
When I click on the model name in the admin view, I get the below error. What does this mean?
AttributeError at /admin/app/tasksx/
'tasksx' object has no attribute 'text'
Request Method: GET
Admin.py
from django.contrib import admin
from .models import tasksx
admin.site.register(tasksx)
Views.py
def create_task(request):
if request.method == 'POST':
creator = request.user
job_title = 'data engineer'
skill_name = request.POST.get('skill_name')
starting = request.POST.get('starting')
description = request.POST.get('description')
target_date = request.POST.get('target_date')
i = tasksx.objects.create(creator=creator, job_title=job_title, skill_name=skill_name, starting=starting, current=starting, description=description, target_date=target_date)
messages.success(request, ('Skill created'))
return redirect('index')
models.py
class tasksx(models.Model):
job_title = models.CharField(max_length=400, default="data")
creator = models.CharField(max_length=400, default="none")
skill_name = models.CharField(max_length=400, default="none")
starting = models.CharField(max_length=400, default="none")
current = models.CharField(max_length=400, default="none")
description = models.CharField(max_length=4000000, default="none")
target_date = models.DateTimeField(default=datetime.now)
def __str__(self):
return self.text
Expanding my comments to avoid extended discussion:
In your tasksx model's __str__ method you are trying to return self.text when you don't have a text field anywhere in the model.
If you want to display the title, modify the method's return to.
def __str__(self):
return self.job_title
Now, if you want to see all fields in the admin interface, you would need to modify your app's admin.py.
admin.py
from django.contrib import admin
from .models import tasksx
class Tasksx_Admin(admin.modelAdmin):
# Add whatever fields you want to display in the admin
# in list_diplay tuple.
list_display = ('job_title', 'creator', 'skill_name', 'starting', 'current', 'description', 'target_date', )
# Register the Taskx_Admin class.
admin.site.register(tasksx, Taskx_Admin)
In the tasksx model you defined:
def __str__(self):
return self.text
But there is no text property in the model.

How to check if data already exists in the table using django

I am new with django framework struggling to compare value from the database.
this are my tables in models.py :
class Post(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE,)
title = models.CharField(max_length=200)
content = models.TextField()
creationDate = models.DateTimeField(auto_now_add=True)
lastEditDate = models.DateTimeField(auto_now=True)
def __str__(self):
return self.title
class Votes(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE,)
post_id = models.ForeignKey(Post, on_delete=models.CASCADE,)
up_vote = models.PositiveIntegerField(default=0, validators=[MinValueValidator(0), MaxValueValidator(1)])
down_vote = models.PositiveIntegerField(default=0, validators=[MinValueValidator(0), MaxValueValidator(1)])
class Meta:
unique_together = (("user","post_id"),)
I have data in the vote tabe like this:
Now what I want is to check in the above table if 'user_id' and 'post_id' already exists in the Votes tabel's rows if the exist throw a message if not add value on upvote or downvote, i gues everyone understand what i want if not please let me know.
something which i tried was this code:
def chk_table():
user_id = request.user
post_id = id
votes_table = Votes.objects.filter(user_id=user_id, post_id= post_id).exists()
return votes_table
but this function is checking in hole table not just in just in one row...
Assuming that, in your urls.py
from django.urls import path
from .views import add_vote
urlpatterns = [
path('post/<int:post_id>/vote/add/', add_vote, name='add-vote'),
]
In your views.py
from django.shortcuts import redirect, render
def add_vote(request, post_id):
if request.method == 'POST':
# receive your POST data here
user_id = request.user.id
post_id = post_id
if not Votes.objects.filter(user_id=user_id, post_id=post_id).exists():
Votes.objects.create(**your_data)
redirect('your-desired-url')
else:
# your logic here
I see you already defined unique_together in Meta so you can use try except
from django.db import IntegrityError
try:
# your model create or update code here
except IntegrityError as e:
if 'unique constraint' in e.message:
# duplicate detected

How to skip an existing object instance when creating resources in bulk python

I am trying to create a resources in bulk. While the resources are created I have the matric_no has to be unique. If the value of an existing matric_no is uploaded together with the some new entries, I get an integrity error 500 because the value already exists and it stops the rest of the values from being created. How can I loop through these values and then check if the value exists, and then skip so that the others can be populated? Here is my code:
**models.py**
from django.db import models
from django.utils.encoding import python_2_unicode_compatible
#python_2_unicode_compatible
class Undergraduate(models.Model):
id = models.AutoField(primary_key=True)
surname = models.CharField(max_length=100)
firstname = models.CharField(max_length=100)
other_names = models.CharField(max_length=100, null=True, blank=True)
card = models.CharField(max_length=100, null=True, blank=True)
matric_no = models.CharField(max_length=20, unique=True)
faculty = models.CharField(max_length=250)
department_name = models.CharField(max_length=250)
sex = models.CharField(max_length=8)
graduation_year = models.CharField(max_length=100)
mobile_no = models.CharField(max_length=150, null=True, blank=True)
email_address = models.CharField(max_length=100)
residential_address = models.TextField(null=True, blank=True)
image = models.CharField(max_length=250,
default='media/undergraduate/default.png', null=True, blank=True)
def __str__(self):
return "Request: {}".format(self.matric_no)
***serializers.py***
from .models import Undergraduate
from .models import Undergraduate
class UndergraduateSerializer(serializers.ModelSerializer):
class Meta:
model = Undergraduate
fields ='__all__'
class CreateListMixin:
"""Allows bulk creation of a resource."""
def get_serializer(self, *args, **kwargs):
if isinstance(kwargs.get('data', {}), list):
print(list)
kwargs['many'] = True
return super().get_serializer(*args, **kwargs)
**api.py**
from .models import Undergraduate
from rest_framework.viewsets import ModelViewSet
from .serializers import CreateListMixin,UndergraduateSerializer
class UndergraduateViewSet(CreateListMixin, ModelViewSet):
queryset = Undergraduate.objects.all()
serializer_class = UndergraduateSerializer
permission_classes = (permissions.IsAuthenticated,)
**urls.py**
from rest_framework.routers import DefaultRouter
from .api import UndergradMassViewSet
router=DefaultRouter()
router.register(r'ug', UndergradMassViewSet)
This is the updated serializer.py
class UndergraduateSerializer(serializers.ModelSerializer):
class Meta:
model = Undergraduate
fields = ('id', 'surname', 'firstname', 'other_names', 'card','matric_no', 'faculty', 'department_name', 'sex', 'graduation_year', 'mobile_no', 'email_address', 'residential_address')
def create(self, validated_data):
created_ids = []
for row in validated_data:
try:
created = super().create(row)
created_ids.append(created.pk)
except IntegrityError:
pass
return Undergraduate.objects.filter(pk__in=[created_ids])
This is how i moved it now
Seriliazers.py
class UndergraduateSerializer(serializers.ModelSerializer):
def create(self, validated_data):
created_ids = []
for row in validated_data:
try:
created = super().create(row)
created_ids.append(created.pk)
except IntegrityError:
pass
return Undergraduate.objects.filter(pk__in=[created_ids])
class Meta:
model = Undergraduate
fields = ('id', 'surname', 'firstname', 'other_names', 'card','matric_no', 'faculty', 'department_name', 'sex', 'graduation_year', 'mobile_no', 'email_address', 'residential_address')
read_only_fields = ('id',)
When the list sent has an existing matric_no , it returns 500 ListSeriaizer is not iterable
You definitely have to implement a custom create() method in your serializer to handle such a case as the serializer's default create method expects one object.
Nonetheless, there is a couple of design decisions to consider here:
You can use bulk_create but it has a lot of caveats which are listed in the docs and it would still raise an integrity error since the inserts are done in one single commit. The only advantage here is speed
You can loop over each object and create them singly. This will solve the integrity issue as you can catch the integrity exception and move on. Here you'll lose the speed in 1
You can also check for integrity issues in the validate method before even moving on to create. In this way, you can immediately return an error response to the client, with information about the offending ro. If everything is OK, then you can use 1 or 2 to create the objects.
Personally, I would choose 2(and optionally 3). Assuming you also decide to chose that, this is how your serializer's create method should look like:
def create(self, validated_data):
created_ids = []
for row in validated_data:
try:
created = super().create(row)
created_ids.append(created.pk)
except IntegrityError:
pass
return Undergraduate.objects.filter(pk__in=[created_ids])
So in this case, only the created objects will be returned as response

"Foreign Keys" across very separate databases in Django

I've writing a Django site that uses two different databases. One is the local, let's call it, "Django", database that stores all of the standard tables from a pretty standard install -- auth, sites, comments, etc. -- plus a few extra tables.
Most of the data, including users, comes from a database on another server, let's call it the "Legacy" database.
I'm looking for suggestions on clean, pythonic ways of connecting the two databases, particularly in regards to users.
I'm using a proxy model, which works great when I can explicitly use it, but I run into problems when I'm accessing the user object as a related object (for example, when using the built-in django comments system).
Here's what the code looks like:
models.py: (points to the Django database)
from django.db import models
from django.conf import settings
from django.contrib.auth.models import User as AuthUser, UserManager as AuthUserManager, AnonymousUser as AuthAnonymousUser
class UserPerson(models.Model):
user = models.OneToOneField(AuthUser, related_name="person")
person_id = models.PositiveIntegerField(verbose_name='Legacy ID')
def __unicode__(self):
return "%s" % self.get_person()
def get_person(self):
if not hasattr(self, '_person'):
from legacy_models import Person
from utils import get_person_model
Person = get_person_model() or Person
self._person = Person.objects.get(pk=self.person_id)
return self._person
person=property(get_person)
class UserManager(AuthUserManager):
def get_for_id(self, id):
return self.get(person__person_id=id)
def get_for_email(self, email):
try:
person = Person.objects.get(email=email)
return self.get_for_id(person.pk)
except Person.DoesNotExist:
return User.DoesNotExist
def create_user(self, username, email, password=None, *args, **kwargs):
user = super(UserManager,self).create_user(username, email, password, *args, **kwargs)
try:
person_id = Person.objects.get(email=email).pk
userperson, created = UserPerson.objects.get_or_create(user=user, person_id=person_id)
except Person.DoesNotExist:
pass
return user
class AnonymousUser(AuthAnonymousUser):
class Meta:
proxy = True
class User(AuthUser):
class Meta:
proxy=True
def get_profile(self):
"""
Returns the Person record from the legacy database
"""
if not hasattr(self, '_profile_cache'):
self._profile_cache = UserPerson.objects.get(user=self).person
return self._profile_cache
objects = UserManager()
legacy_models.py: (points to the "Legacy" database)
class Person(models.Model):
id = models.AutoField(primary_key=True, db_column='PeopleID') # Field name made lowercase.
code = models.CharField(max_length=40, blank=True, db_column="person_code", unique=True)
first_name = models.CharField(max_length=50, db_column='firstName', blank=True) # Field name made lowercase.
last_name = models.CharField(max_length=50, db_column='lastName', blank=True) # Field name made lowercase.
email = models.CharField(max_length=255, blank=True)
def __unicode__(self):
return "%s %s" % (self.first_name, self.last_name)
def get_user(self):
from models import User
if not hasattr(self,'_user'):
self._user = User.objects.get_for_id(self.pk)
return self._user
user = property(get_user)
class Meta:
db_table = u'People'
I've also whipped up my own middleware, so request.user is the proxy User object also.
The real problem is when I'm using something that has user as a related object, particularly in a template where I have even less control.
In the template:
{{ request.user.get_profile }}
{# this works and returns the related Person object for the user #}
{% for comment in comments %} {# retrieved using the built-in comments app %}
{{ comment.user.get_profile }}
{# this throws an error because AUTH_PROFILE_MODULE is not defined by design #}
{% endfor %}
Short of creating a wrapped version of the comments system which uses my proxy User model instead, is there anything else I can do?
Here's how I resolved it. I stopped using the User proxy altogether.
models.py:
from django.db import models
from legacy_models import Person
from django.contrib.auth.models import User
class UserPerson(models.Model):
user = models.OneToOneField(User, related_name="person")
person_id = models.PositiveIntegerField(verbose_name='PeopleID', help_text='ID in the Legacy Login system.')
def __unicode__(self):
return "%s" % self.get_person()
def get_person(self):
if not hasattr(self, '_person'):
self._person = Person.objects.get(pk=self.person_id)
return self._person
person=property(get_person)
class LegacyPersonQuerySet(models.query.QuerySet):
def get(self, *args, **kwargs):
person_id = UserPerson.objects.get(*args, **kwargs).person_id
return LegacyPerson.objects.get(pk=person_id)
class LegacyPersonManager(models.Manager):
def get_query_set(self, *args, **kwargs):
return LegacyPersonQuerySet(*args, **kwargs)
class LegacyPerson(Person):
objects = LegacyPersonManager()
class Meta:
proxy=True
and legacy_models.py:
class Person(models.Model):
id = models.AutoField(primary_key=True, db_column='PeopleID') # Field name made lowercase.
code = models.CharField(max_length=40, blank=True, db_column="person_code", unique=True)
first_name = models.CharField(max_length=50, db_column='firstName', blank=True) # Field name made lowercase.
last_name = models.CharField(max_length=50, db_column='lastName', blank=True) # Field name made lowercase.
email = models.CharField(max_length=255, blank=True)
def __unicode__(self):
return "%s %s" % (self.first_name, self.last_name)
def get_user(self):
from models import User
if not hasattr(self,'_user'):
self._user = User.objects.get_for_id(self.pk)
return self._user
def set_user(self, user=None):
self._user=user
user = property(get_user, set_user)
class Meta:
db_table = u'People'
Finally, in settings.py:
AUTH_PROFILE_MODULE = 'myauth.LegacyPerson'
This is a simpler solution, but at least it works! It does mean that whenever I want the legacy record I have to call user_profile, and it means that there's an additional query for each user record, but this is a fair trade-off because actually it isn't very likely that I will be doing a cross check that often.