How to store social usernames/links in Django? - django

I have a personal blog written with Django. I want to make my social links/usernames dynamic so I can change them whenever I want.
I'm doing this with charfields. I'm adding new charfield for each social username/link field then my template's getting these usernames to show them in a tags. It's okay but I think it's not the easiest way.
Am I wrong or there is a better way to do this?

Maybe it would be easier to create a model for it. That way you would be able to add/remove social links without having to touch the code.
from django.conf import settings
from django.db import models
class SocialProfile(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='social_profiles')
network = models.CharField(max_length=100)
username = models.CharField(max_length=100)
url = models.URLField(max_length=500)
Then if you are using Django Admin, you could add this model as a TabularInline of the User model for example.
In your templates you could render the links dynamically:
{% for profile in request.user.social_profiles.all %}
{{ profile.username }}
{% endfor %}
Something like that.

Related

Django Social Auth - Referring to usersocialauth for foreign key in model

I'm using the social_django package for the first time. The project only requires authentication for the application through Facebook so I implemented the SOCIAL_AUTH_FACEBOOK method into my app, which retrieves basic info like username, first name, last name, email address. I also get the user's Facebook profile picture through SOCIAL_AUTH_FACEBOOK_EXTRA_DATA.
I want to figure out how to refer to the usersocialauth model as a parent key in my model. Right now, it's associating everything to auth_user model, which doesn't allow me to access the Facebook profile picture in the template.
Here is what I am doing at the moment:
models.py
from social_django import models as oauth_models
class Review(models.Model):
...
author = models.ForeignKey(oauth_models.USER_MODEL,
on_delete=models.CASCADE)
I am able to access the basic fields in the template through <p>{{ review.author.name }}</p>, but to see the profile picture, I have to do something like this:
{% for author in backends.associated %}
<img src="{{ author.extra_data.picture.data.url }}" alt="">
{% endfor %}
I would like to simplify this and just refer to the usersocialauth model so I can access all the data from one place in the template.
Found an easier solution.
I can keep ForeignKey relationship with the regular user model and use author.social_auth.all.0.extra_data.picture.data.url in the template.

Internationalizing a Django class-based generic view (CreateView)?

I am using Django 1.9 class-based generic views, for example CreateView. When I visit the "create" page, some parts are translated (into French in my example), so I know my config and wiring is correct, but the form fields (auto-named by the view) are not (i.e. form.as_p).
How can I get form fields to be used from my translations file? (For example, "Name" is a field, already translated, but not picked up by the form.as_p).
One answer is to list out the fields individually in the template with {% trans %} tags. I was hoping to avoid that.
My example is similar to the one in the docs, so let me repeat that example here. First, code:
from django.views.generic.edit import CreateView
from myapp.models import Author
class AuthorCreate(CreateView):
model = Author
fields = ['name']
Then display template:
<form action="" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Save" />
</form>
Have a look at the Lazy Translation:
This is essential when calls to these functions are located in code paths that are executed at module load time.
This is something that can easily happen when defining models, forms and model forms, because Django implements these such that their fields are actually class-level attributes.
So, if you have a form, you can use ugettext_lazy to translate:
from django.db import models
from django.utils.translation import ugettext_lazy as _
class MyThing(models.Model):
name = models.CharField(help_text=_('This is the help text'))
You can mark names of ForeignKey, ManyToManyField or OneToOneField relationship as translatable by using their verbose_name options:
class MyThing(models.Model):
kind = models.ForeignKey(
ThingKind,
on_delete=models.CASCADE,
related_name='kinds',
verbose_name=_('kind'),
)

Django user with custom data in multiple apps

Customer User models was great but if you want to build a project combining multiple apps, each app can assume it's going to have the user model as part of it's models. My plan is to revert to the standard django User and have a profile in each app.
eg.
app1.models.py
from django.contrib.auth.models import User
Class App1User(models.Model):
user = models.OneToOne(User)
special = models.CharField( some field that relates to the user in this app)
app2.models.py
from django.contrib.auth.models import User
Class App2User(models.Model):
user = models.OneToOne(User)
another = models.CharField( some field that relates to the user in this app)
etc.
Then add code to go and get the relevant profile data when needed, maybe adding some middleware or template context processors. Before I go down this route I wanted to check this is the most Djangoeque solution?
Imho yes, you doing it in the right way.
And you don't need any middleware or context processors to get relevant data for the user. OneToOne field is easily accessible as the attribute of the user instance:
{{ user.app1user.special }}
{{ user.app2user.another }}

Django admin checkbox with multiple select

I have a Django app. Pretty basic one at that.
In the model I have a class for items and a class for groups. The groups has a many to many for the items:
items = models.ManyToManyField(item, verbose_name="list of items", max_length=100000, blank=True)
When I add this to the admin section I would like to have a checkbox with multiple select. Is this possible. All of the solutions I have looked at don't sow it in the context of an admin page too. The Django admin page is all I need it to work on as I am not making any custom, public facing pages.
What is the easiest and most simple solution to replace the multiple select box with a multiple checkbox.
PS. I am relatively in-experienced with Django so I need to see what I need to import in the model and admin.
Thanks
If you know how to do it for a standard modelform, you know how to do it in an admin page too, as they are based on normal forms.
Just define the form as normal, then tell the admin to use it for your model:
class MyModelAdmin(admin.ModelAdmin):
form = MyFormWithTheMultipleSelect
way based on overriding admin templates
/myproject/templates/admin/myapp/mymodel/change_form.html
{% extends "admin/change_form.html" %}
{{ block.super }}
<script type='text/javascript' src='/media/js/jquery.js'></script>
<script>
$(document).ready(function(){
myselect = $("#id_M2M_FIELD_NAME");
// here you manipulating with your multiple select,
// and convert it to checkboxes, or something else.
})
</script>
{% endblock %}

Extend flatpages for a specific application

I have a portfolio application that lists projects and their detail pages. Every project generally has the same information (gallery, about etc. ), but sometimes the user might want to add extra information for a particularly large project, maybe an extra page about the funding of that page for example.
Would it be possible to create an overwritten flatpages model within my portfolio app that forces any flatpages created within that application to always begin with /portfolio/project-name/flat-page. I could then simply pass the links to those flatpages associated with the project to the template so any flatpage the user generates will automatically be linked to from the project page.
EDIT
I have it somewhat working now
So I overwrite the FlatPage model in my portfolio app as described:
from django.contrib.flatpages.models import FlatPage
from project import Project
from django.db import models
from django.contrib.sites.models import Site
class ProjectFlatPage(FlatPage):
prefix = models.CharField(max_length=100)
project = models.ForeignKey(Project)
which allows me to associate this flatpage with a particular project,
Then I overwrite the save method to write all the extra information when a user saves (needs to be tidied up):
def save(self, force_insert=False, force_update=False):
self.url = u"%s%s/" % (self.project.get_absolute_url(),self.prefix)
self.enable_comments = False
self.registration_required = False
self.template_name = 'project/project_flatpage.html'
super(FlatPage, self).save(force_insert, force_update)
and I scaleback the admin to just allow the important stuff:
class ProjectFlatPageForm(forms.ModelForm):
prefix = forms.RegexField(label=_("Prefix"), max_length=100, regex=r'^[a-z0-9-]+$'),
class Meta:
model = ProjectFlatPage
class ProjectnFlatPageAdmin(admin.ModelAdmin):
form = ProjectFlatPageForm
so now the user can add a flat page inside my app and associate it with a particular project.
In the admin, they just enter a slug for the page and it automatically gets appended through the save() method like: /projects/project-name/flat-page-name/
The remaining problem is on the template end. I can access the normal flatpage information through the given template tags {{ flatpage.title }} and {{ flatpage.content }} put I have no access to the extra fields of the inherited model (i.e. the project field)
Is there anyway around this?
EDIT2
Having thought about it, the easiest way is to write a template tag to find the projectFlatPage associated with the flatpage and get access to it from there. A bit like overwritting the default flatpages template tags
re the 'Edit 2' part of your question... since your custom flatpage model inherits from FlatPage there is an automatic one-to-one field relation created between them by Django.
So in your template, if you know that the flatpage object passed in is one of your customised ones you can access your extra attributes by:
{{ flatpage.projectflatpage.project }}
Of course. Just write your own flatpage-model, for example:
from django.contrib.flatpages.models import FlatPage
class MyFlatPage(FlatPage):
prefix = models.CharField(max_length=100, editable=False)
url = models.CharField(_('URL'), max_length=100, db_index=True, editable=False)
Then add a proper MyFlatPageAdmin to your admin.py file (if you want to, you can import the flatpageadmin from django.contrib.flatpages.admin and inherit from it). After all, you're using the flatpage-model, but overwrite the urls-field. Now add a signal, which concats the prefix and a automatically generated url suffix to the url (like the object id). You can now add the custom flatpage like:
flatpage = MyFlatPage(prefix='/portfolio/my-super-project/')
Everything clear now?
edit 1
As you can read in the documentation, every flatpage should be a projectflatpage and vice versa.