I am using Django Channels and I want to be able to save additional fields to the database along with the json data of the post.
I have a foreign key in my Postmie model that points to email field in my user model. Postmie is the model responsible for saving posts to the database. The Foreign key creates a field called email_id. While I am saving posts to the database I want to also grab the email of the user making the post and save it in the database as well. How can I go about doing this? I am not using Django forms.
My Postmie model is the same as the one in the Django Channels tutorial Post found here, the only difference is that my model has an extra foreign key pointing to the email field in my user model.
email=request.user.email does not work. I was thinking about putting the email in a hidden field, but that does not seem safe to me.
The method I am using is practically the same method in the Django Channels tutorial found here consumers.py. Everything works but I am not able to enter other fields in the database for posts.
def save_post(message, slug, request):
"""
Saves vew post to the database.
"""
post = json.loads(message['text'])['post']
email = request.user.email
feed = Feed.objects.get(slug=slug)
Postmie.objects.create(feed=feed, body=post email_id=email)
Postmie model:
#python_2_unicode_compatible
class Postmie(models.Model):
# Link back to the main blog.
feed = models.ForeignKey(Feed, related_name="postmie")
email = models.ForeignKey(Usermie,
to_field="email",
related_name="postmie_email", max_length=50)
subject = models.CharField(max_length=50)
classs = models.CharField(max_length=50, null=True, blank=True)
subclass = models.CharField(max_length=50, null=True, blank=True)
title = models.CharField(max_length=60, null=True, blank=True)
body = models.TextField()
date_created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
def __str__(self):
return "#%i: %s" % (self.id, self.body_intro())
def post_email(self):
return self.email
def post_subject(self):
return self.subject
def post_datetime(self):
return self.datetime
def get_absolute_url(self):
"""
Returns the URL to view the liveblog.
"""
return "/feed/%s/" % self.slug
def body_intro(self):
"""
Short first part of the body to show in the admin or other compressed
views to give you some idea of what this is.
"""
return self.body[:50]
def html_body(self):
"""
Returns the rendered HTML body to show to browsers.
You could change this method to instead render using RST/Markdown,
or make it pass through HTML directly (but marked safe).
"""
return linebreaks_filter(self.body)
def send_notification(self):
"""
Sends a notification to everyone in our Liveblog's group with our
content.
"""
# Make the payload of the notification. We'll JSONify this, so it has
# to be simple types, which is why we handle the datetime here.
notification = {
"id": self.id,
"html": self.html_body(),
"date_created": self.date_created.strftime("%a %d %b %Y %H:%M"),
}
# Encode and send that message to the whole channels Group for our
# feed. Note how you can send to a channel or Group from any part
# of Django, not just inside a consumer.
Group(self.feed.group_name).send({
# WebSocket text frame, with JSON content
"text": json.dumps(notification),
})
def save(self, *args, **kwargs):
"""
Hooking send_notification into the save of the object as I'm not
the biggest fan of signals.
"""
result = super(Postmie, self).save(*args, **kwargs)
self.send_notification()
return result
Assuming that Usermie is your user model. This means that you have AUTH_USER_MODEL='yourapp.Usermie' in settings.py
If you are not using to_field, You can do,
I think you need to do the following
Postmie.objects.create(feed=feed, body=post email=request.user)
Or you can do
Postmie.objects.create(feed=feed, body=post email_id=request.user.id)
You should know that every foreign key is usually represented on the database with the name of the field appended with _id. This is how Django put the foreign key. Usually you should use the ORM of Django directly.
If you are using to_field:Only in Django > 1.10
According to the documentation, email should be unique.
If to_field is changed after Postmie is created. Please make sure that all values in the column have the new corresponding value.
Related
I have a task to create a simple post API to send a visitor messages through a contact form that contain fields like full_name,address,phone etc. But instead of creating a model, I have to use an already existing model which has a Jsonfield. Now what I need to do is to use that jsonfield which will have all the fields like name, address etc.
class Core(models.Model):
"""
Model that saves the corresponding credentials for the slug.
"""
slug = models.CharField(max_length=255, null=False)
example = models.JSONField(null=False, default=dict)
def __str__(self) -> str:
return self.slug
If it was done in a regular way by creating a model, it would have been like this.
class Contacts(models.Model):
full_name = models.CharField(max_length=100,blank=True,default="")
email = models.EmailField()
phone = models.CharField(max_length= 16)
address = models.CharField(max_length=255,blank=True,default="")
message = RichTextField()
def __str__(self):
return self.email
Now, how should I send these fields data in a dictionary without in that JsonField without creating a Contacts model?
First of all, this question is not clear. Please ask your question in a clearer way. I hope the way below helps you.
This field keeps data like;
{"full_name":"John Doe", "email": "johndoe#doe.com", "phone":"XXXXXXXXXXX"}
You may create dictionary and assign to field. Also you may create json data like this;
json_example = json.dumps(full_name="John Doe, email="johndoe#doe.com, phone="XXXXXXXXXXX")
and then create a Core object ;
core = Core(example = json_example)
core.save()
In my django template <p>This user is unsubscribed {{sub.is_unsubscribed}}</p> always displays "This user is unsubcribed False" even when it should show True based on the following models.py
from django.shortcuts import get_object_or_404
class Subscriber(models.Model):
email = models.CharField(max_length=12)
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
create_date = models.DateTimeField(auto_now_add=True)
def is_unsubscribed(self):
try:
get_object_or_404(MasterUnsubscriber, unsubcriber_email=self.email)
return True
except:
return False
def __str__(self):
return self.email
class MasterUnsubscriber(models.Model):
unsubscriber_email= models.CharField(max_length=12)
And for structural reasons of my app, I do not want to move the unsubscribe to the Subscriber model as a boolean. How can this be resolved while keeping same model formats.
get_object_or_404 will raise an error if there is no element at all, or when there are multiple such elements, since the underlying implementation is to use .get(..). You can make use of .exists() instead:
class Subscriber(models.Model):
# …
def is_unsubscribed(self):
return MasterUnsubscriber.objects.filter(unsubscriber_email=self.mail).exists()
That being said, I would advice to make use a ForeignKey [Django-doc] to the subscriber, not by matching the email address. This will be inefficient, since search on a non-indexed column is slow, and furthermore if the user later changes their email, then the all of a sudden, these can be subscribed again. Django also has convenient ways to filter or make aggregates on related objects, so you get more out of the Django ORM.
My project is a social networking site that can send requests to friends and make friends.
I have extended django's existing user model using oneToone field .
So far i've been able to do the above said thing but when ever a user accepts the request , Both the user who sent request and also the user accepted it must increment a value in their extended user model which stores the value of their friends count .
I'm facing difficulties trying to solve this .
I've also used signals but it doesn't work .
Here is my code:
models.py:
class Friends(models.Model):
"""Model for saving relationship of user and friends"""
request_id = models.ForeignKey(User,on_delete=models.CASCADE,related_name='current_user')
friend_id = models.ForeignKey(User,on_delete=models.CASCADE,related_name='user_friend')
created_on = models.DateTimeField(auto_now_add=True,auto_now=False)
class Meta:
verbose_name_plural = "Friends"
def __str__(self):
return str(self.friend_id)
class Profile(models.Model):
user = models.OneToOneField(User,related_name='profile',on_delete=models.CASCADE)
location = models.CharField(max_length=30,blank=True)
friends_count = models.PositiveIntegerField(default=0)
profile_pic = models.ImageField(upload_to='profile_pics/',blank=True,null=True)
def natural_key(self):
return (self.user.username,)
signals.py:
#receiver(post_save,sender=Friends)
def update_friends_count(sender,instance,created,**kwargs):
if created:
user_profile = Profile(user = instance.request_id)
user_profile.friends_count=F('friends_count')+1
user_profile.save()
Any help would be greatly appreciated!!!!! Thank you in advance!!!
You were initializing a new instance of Profile every time a friend is made. Instead you can use get_or_create to generate a profile or retrieve the one associated with that id. Next, you want to update both users so fetch the other update the counts and save.
#receiver(post_save,sender=Friends)
def update_friends_count(sender,instance,created,**kwargs):
if created:
user_profile, profile_created = Profile.objects.get_or_create(user = instance.request_id)
user_profile.friends_count=F('friends_count')+1
user_profile.save()
friend_profile, profile_created = Profile.objects.get_or_create(user = instance.friend_id)
friend_profile.friends_count=F('friends_count')+1
friend_profile.save()
With Q filter and update
Profile.objects.filter(
Q(user=instance.request_id) |
Q(user=instance.friend_id)
).update(
friends_count=F('friends_count')+1
)
This last query uses the django.db.models Q object to make an SQL OR statement to retrieve the two profile instances; that of the requested and the requester: the update call acts on the query and updates all instances in the list
Hi I have two related models, I need to save it depends on json data from Angular.
Here is models:
Class Company(models.Model):
name = models.CharField(
max_length=255, )
class ContactPerson(models.Model):
company = models.ForeignKey(
Company,
related_name='contact_persons', )
name = models.CharField(
max_length=255, )
Here is part of view:
class CompanyCreate(JsonView):
#JsonView write by me, contains some methods
def post(self, *args, **kwargs):
data = json.loads(self.request.body)
company = CompanyForm(data=data['company'])
contacts = ContactForm(data=data['contacts'])
if company.is_valid():
company.save()
if contacts.is_valid():
contacts.save(commit=False)
contacts.company = company
contacts.save()
return HttpResponse()
Company is saving, but I cant valid contacts form, because I cant get company.id from first form.
I don't think you could save them at once because:
They are instances that has foreign key relationships, so one wouldn't exist before the other.
They are 3 different model instances so it doesn't make sense to combine them in one form.
If you just want to save the ones that are valid and reject the ones that are invalid, what you currently do is enough with one change, capturing the return value of save() function:
class CompanyCreate(JsonView):
#JsonView write by me, contains some methods
def post(self, *args, **kwargs):
data = json.loads(self.request.body)
company_form = CompanyForm(data=data['company'])
contacts_form = ContactForm(data=data['contacts'])
if company_form.is_valid():
company = company_form.save()
if contacts.is_valid():
contacts = contacts_form.save(commit=False)
contacts.company = company
contacts.save()
return HttpResponse()
If you want "all or none" logic, meaning you either save everything if everything is valid, otherwise don't save anything, you should exclude the foreign key on each ModelForm, so that when you valid the forms, they ignore the validation of existence of ForeignKey but not all other fields. See if that makes sense.
In my model, I have the following M2M field
class FamilyMember(AbstractUser):
...
email_list = models.ManyToManyField('EmailList', verbose_name="Email Lists", blank=True, null=True)
...
The EmailList table looks like this:
class EmailList(models.Model):
name = models.CharField(max_length=50, default='My List')
description = models.TextField(blank=True)
is_active = models.BooleanField(verbose_name="Active")
is_managed_by_user = models.BooleanField(verbose_name="User Managed")
In the app, the user should only see records that is_active=True and is_managed_by_user=True.
In the Admin side, the admin should be able to add a user to any/all of these groups, regardless of the is_active and is_managed_by_user flag.
What happens is that the Admin assigns a user to all of the email list records. Then, the user logs in and can only see a subset of the list (is_active=True and is_managed_by_user=True). This is expected behavior. However, what comes next is not.
The user deselects an email list item and then saves the record. Since M2M_Save first clears all of the m2m records before it calls save() I lose all of the records that the Admin assigned to this user.
How can I keep those? I've tried creating multiple lists and then merging them before the save, I've tried passing the entire list to the template and then hiding the ones where is_managed_by_user=False, and I just can't get anything to work.
What makes this even more tricky for me is that this is all wrapped up in a formset.
How would you go about coding this? What is the right way to do it? Do I filter out the records that the user shouldn't see in my view? If so, how do I merge those missing records before I save any changes that the user makes?
You might want to try setting up a model manager in your models.py to take care of the filtering. You can then call the filter in your views.py like so:
models.py:
class EmailListQuerySet(models.query.QuerySet):
def active(self):
return self.filter(is_active=True)
def managed_by_user(self):
return self.filter(is_managed_by_user=True)
class EmailListManager(models.Manager):
def get_queryset(self):
return EmailListQuerySet(self.model, using=self._db)
def get_active(self):
return self.get_queryset().active()
def get_all(self):
return self.get_queryset().active().managed_by_user()
class EmailList(models.Model):
name = models.CharField(max_length=50, default='My List')
description = models.TextField(blank=True)
is_active = models.BooleanField(verbose_name="Active")
is_managed_by_user = models.BooleanField(verbose_name="User Managed")
objects = EmailListManager()
views.py:
def view(request):
email = EmailList.objects.get_all()
return render(request, 'template.html', {'email': email})
Obviously there is outstanding data incorporated in my example, and you are more than welcome to change the variables/filters according to your needs. However, I hope the above can give you an idea of the possibilities you can try.
In your views you could do email = EmailList.objects.all().is_active().is_managed_by_user(), but the loading time will be longer if you have a lot of objects in your database. The model manager is preferred to save memory. Additionally, it is not reliant on what the user does, so both the admin and user interface have to talk to the model directly (keeping them in sync).
Note: The example above is typed directly into this answer and has not been validated in a text editor. I apologize if there are some syntax or typo errors.